2016-07-23 5 views
3

私のデータベースには、多くの内部リンクを持つcontenfieldsがあります。これをいただきまし交換することが期待されMySQLは指定されたドメインの.htmlリンクを置き換えます

www.mydomain.de/somepage.html -> www.mydomain.de/page/ 
www.mydomain.de/subfolder/page.html -> www.mydomain.de/subfolder/page/ 
www.mydomain.de/link.html?param=1 -> www.mydomain.de/page/?param=1 
www.mydomain.de/another-link.html#hash -> www.mydomain.de/page/#hash 
私はドメインを尊重すべきwww.mydomain.de/page/するwww.mydomain.de/page.htmlからリンク構造を変更するが、文を交換する必要が

他のすべてのリンクは、ここでは、いくつかの例そのままにする必要がありますが、ウェブ上の任意のリンクのようになります。

www.some-domain.de/link.html  
www.another-domain.com/somelink.html 

1 contentfieldで異なるリンクが存在することができます:

<p>If you want to read more, click 
<a href="http://www.mydomain.de/page.html">here</a> 
or there <a href="http://www.another-domain.com/somelink.html">there</a> 

これは置き換えやっている:私のアイデア

UPDATE tablename 
SET contentfield = REPLACE(contentfield, '.html', '/') 

(しかし、彼らのためにステートメントを作成する方法がわからない):前100文字以内「はmydomain発見された

  • 。 MYDOMAINド「『mydomain.de』の 『.htmlを』の数見つけ=数は、それがすべてに一致する100%である必要はありません

を見つけ

  • 」 .de 'リンクでは、私は90%に満足していますが、外部リンクに間違った置換があってはいけません。

  • +0

    これは、MySQL/ANSI SQLで100%を行わなければならない場合、私は今/ Oクエリ文字列wのすべての可能なURL(場合、それは当然のない限り...行うことができないと思いますそれはやや些細なことだろう)。しかし、あなたがしなければ...問題は、あなたは正規表現でドメイン(とURL)を一致させることができますが、あなたはそれをいくつかの中間変数/テーブル/に抽出することも、正規表現で置き換えることもできません。いくつかの外部スクリプトが作業をすることを許可したいのであれば、それはほとんど問題にならないでしょう。ストアドプロシージャが可能な場合は解決策があるかもしれませんが、おそらく醜いでしょう。 – Jakumi

    +0

    'contentfield'には' www.mydomain.de 'の何回まで表示されますか?未知の場合、これは単に 'update'ステートメントで行うことはできません。 – Blank

    +0

    @JPGちょうど更新を複数回実行することはできますか? – Jakumi

    答えて

    2

    UPDATE:

    http://stevettt.blogspot.co.uk/2018/02/a-mysql-regular-expression-replace.html


    は、私はあなたが求めているすべての結果を生み出すべきだと思い、次のRextesterフィドルを参照してください:は現在、ブログの記事にこれを作りました

    Rextester Demo

    説明

    これにはパターン置換機能が必要ですが、残念ながらMySQL doesn't provide such a thingです。だから私は1つ(かなり十分ではなかった別のものに基づいて)を書いて、それを投稿したhere。参照された答えで述べたように、この関数には後方参照での捕捉グループの置換を許可しないという制限があります。それゆえ、それは、フィデルに、置換のために見つかったマッチで再帰的な置換を実行することを可能にするさらなるパラメータを取るように、わずかに適合されている。 (this excellent answerのように正規表現で許可されたURLパス文字の使用に注意してください)。

    更新SQL

    次のSQLは、以下の機能を使用して、テーブルのデータを更新します。

    UPDATE urls 
    SET url = reg_replace(
        url, 
        'www\\.mydomain\\.de/[-A-Za-z0-9\\._~!\\$&''\\(\\)\\*\\+,;=:@%/]+\\.html', 
        '/[^/]+\\.html', 
        '/page/', 
        TRUE, 
        22, -- Min match length = www.mydomain.de/?.html = 22 
        0, -- No max match length 
        7, -- Min sub-match length = /?.html = 7 
        0 -- No max sub-match length 
    ); 
    

    機能コード

    デモで使用されるUDFコードも掲載されています以下。注:UDFはonly stored procedures will allow recursion in MySQL以降、ストアドプロシージャに委任します。

    -- ------------------------------------------------------------------------------------ 
    -- USAGE 
    -- ------------------------------------------------------------------------------------ 
    -- SELECT reg_replace(<subject>, 
    --     <pattern>, 
    --     <subpattern>, 
    --     <replacement>, 
    --     <greedy>, 
    --     <minMatchLen>, 
    --     <maxMatchLen>, 
    --     <minSubMatchLen>, 
    --     <maxSubMatchLen>); 
    -- where: 
    -- <subject> is the string to look in for doing the replacements 
    -- <pattern> is the regular expression to match against 
    -- <subpattern> is a regular expression to match against within each 
    --    portion of text that matches <pattern> 
    -- <replacement> is the replacement string 
    -- <greedy> is TRUE for greedy matching or FALSE for non-greedy matching 
    -- <minMatchLen> specifies the minimum match length 
    -- <maxMatchLen> specifies the maximum match length 
    -- <minSubMatchLen> specifies the minimum match length 
    -- <maxSubMatchLen> specifies the maximum match length 
    -- (minMatchLen, maxMatchLen, minSubMatchLen and maxSubMatchLen are used to improve 
    -- efficiency but are optional and can be set to 0 or NULL if not known/required) 
    -- Example: 
    -- SELECT reg_replace(txt, '[A-Z0-9]{3}', '[0-9]', '_', TRUE, 3, 3, 1, 1) FROM tbl; 
    DROP FUNCTION IF EXISTS reg_replace; 
    DELIMITER // 
    CREATE FUNCTION reg_replace(subject VARCHAR(21845), pattern VARCHAR(21845), 
        subpattern VARCHAR(21845), replacement VARCHAR(21845), greedy BOOLEAN, 
        minMatchLen INT, maxMatchLen INT, minSubMatchLen INT, maxSubMatchLen INT) 
    RETURNS VARCHAR(21845) DETERMINISTIC BEGIN 
        DECLARE result VARCHAR(21845); 
        CALL reg_replace_worker(
        subject, pattern, subpattern, replacement, greedy, minMatchLen, maxMatchLen, 
        minSubMatchLen, maxSubMatchLen, result); 
        RETURN result; 
    END;// 
    DELIMITER ; 
    
    DROP PROCEDURE IF EXISTS reg_replace_worker; 
    DELIMITER // 
    CREATE PROCEDURE reg_replace_worker(subject VARCHAR(21845), pattern VARCHAR(21845), 
        subpattern VARCHAR(21845), replacement VARCHAR(21845), greedy BOOLEAN, 
        minMatchLen INT, maxMatchLen INT, minSubMatchLen INT, maxSubMatchLen INT, 
        OUT result VARCHAR(21845)) 
    BEGIN 
        DECLARE subStr, usePattern, useRepl VARCHAR(21845); 
        DECLARE startPos, prevStartPos, startInc, len, lenInc INT; 
        SET @@SESSION.max_sp_recursion_depth = 2; 
        IF subject REGEXP pattern THEN 
        SET result = ''; 
        -- Sanitize input parameter values 
        SET minMatchLen = IF(minMatchLen < 1, 1, minMatchLen); 
        SET maxMatchLen = IF(maxMatchLen < 1 OR maxMatchLen > CHAR_LENGTH(subject), 
             CHAR_LENGTH(subject), maxMatchLen); 
        -- Set the pattern to use to match an entire string rather than part of a string 
        SET usePattern = IF (LEFT(pattern, 1) = '^', pattern, CONCAT('^', pattern)); 
        SET usePattern = IF (RIGHT(pattern, 1) = '$', usePattern, CONCAT(usePattern, '$')); 
        -- Set start position to 1 if pattern starts with^or doesn't end with $. 
        IF LEFT(pattern, 1) = '^' OR RIGHT(pattern, 1) <> '$' THEN 
         SET startPos = 1, startInc = 1; 
        -- Otherwise (i.e. pattern ends with $ but doesn't start with ^): Set start pos 
        -- to the min or max match length from the end (depending on "greedy" flag). 
        ELSEIF greedy THEN 
         SET startPos = CHAR_LENGTH(subject) - maxMatchLen + 1, startInc = 1; 
        ELSE 
         SET startPos = CHAR_LENGTH(subject) - minMatchLen + 1, startInc = -1; 
        END IF; 
        WHILE startPos >= 1 AND startPos <= CHAR_LENGTH(subject) 
         AND startPos + minMatchLen - 1 <= CHAR_LENGTH(subject) 
         AND !(LEFT(pattern, 1) = '^' AND startPos <> 1) 
         AND !(RIGHT(pattern, 1) = '$' 
          AND startPos + maxMatchLen - 1 < CHAR_LENGTH(subject)) DO 
         -- Set start length to maximum if matching greedily or pattern ends with $. 
         -- Otherwise set starting length to the minimum match length. 
         IF greedy OR RIGHT(pattern, 1) = '$' THEN 
         SET len = LEAST(CHAR_LENGTH(subject) - startPos + 1, maxMatchLen), lenInc = -1; 
         ELSE 
         SET len = minMatchLen, lenInc = 1; 
         END IF; 
         SET prevStartPos = startPos; 
         lenLoop: WHILE len >= 1 AND len <= maxMatchLen 
           AND startPos + len - 1 <= CHAR_LENGTH(subject) 
           AND !(RIGHT(pattern, 1) = '$' 
             AND startPos + len - 1 <> CHAR_LENGTH(subject)) DO 
         SET subStr = SUBSTRING(subject, startPos, len); 
         IF subStr REGEXP usePattern THEN 
          IF subpattern IS NULL THEN 
          SET useRepl = replacement; 
          ELSE 
          CALL reg_replace_worker(subStr, subpattern, NULL, replacement, greedy, 
              minSubMatchLen, maxSubMatchLen, NULL, NULL, useRepl); 
          END IF; 
          SET result = IF(startInc = 1, 
              CONCAT(result, useRepl), CONCAT(useRepl, result)); 
          SET startPos = startPos + startInc * len; 
          LEAVE lenLoop; 
         END IF; 
         SET len = len + lenInc; 
         END WHILE; 
         IF (startPos = prevStartPos) THEN 
         SET result = IF(startInc = 1, CONCAT(result, SUBSTRING(subject, startPos, 1)), 
             CONCAT(SUBSTRING(subject, startPos, 1), result)); 
         SET startPos = startPos + startInc; 
         END IF; 
        END WHILE; 
        IF startInc = 1 AND startPos <= CHAR_LENGTH(subject) THEN 
         SET result = CONCAT(result, RIGHT(subject, CHAR_LENGTH(subject) + 1 - startPos)); 
        ELSEIF startInc = -1 AND startPos >= 1 THEN 
         SET result = CONCAT(LEFT(subject, startPos), result); 
        END IF; 
        ELSE 
        SET result = subject; 
        END IF; 
    END;// 
    DELIMITER ; 
    
    +1

    あなたの完全な答えをたくさんありがとうございました! –

    2

    これは必要な操作ですか?

    質問の例では機能するはずです。

    好きな場合は、実際には ".html"が含まれている行のみを条件に一致させることができます。あなたは

    UPDATE tablename 
    SET contentfield = REPLACE(contentfield, '.html', '/') 
    where contentfield like 'www.mydomain.de%' 
    AND contentfield like '%html%' 
    AND (contentfield not like 'www.another-domain.com/somelink%' OR 
         contentfield not like 'www.another-domain.com/subfolder/link%') 
    
    +0

    contentfieldにはさらに多くのリンクが含まれている可能性があります - 質問に例を追加しました –

    0

    私はちょうど/の/ etc優れ++その後、メモ帳を使用し、CSVまたは何かにテーブルをエクスポートします。
    '.html'を '/'に置き換える内部ツール。

    その後、SQLにインポートし直します。

    また、mysqlは正規表現をサポートしているため、.htmlを含むドメインを検索できます。

    mydomain.de[^s]+.html 
    
    +0

    contentfieldにはさらに多くのリンクが含まれています - 質問の例を追加しました –

    +0

    残念ながら "www.mydomain.de"は文字列として "another-domain.com"ウェブ上の任意のリンクです –

    +0

    あなたは取得するためにいくつかのlogiを持っています.. "another-domain.com"? ..もしそうなら、この論理を使うことができます。 – scaisEdge

    1

    のように使用することができます

    WHERE contentfield like 'www.mydomain.de/%.html%' 
    
    関連する問題