MySQL remplacer.liens html d'un domaine donné

dans ma base de données il y a des contentfields avec beaucoup de liens internes. Je dois changer la structure du lien de www.mydomain.de/page.html pour www.mydomain.de/page/, mais remplacer l'énoncé doit respecter le domaine:

c'est ce qui devrait être remplacé:

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

tous les autres liens devraient être intacts, voici quelques exemples, mais pourrait être n'importe quel lien sur le web:

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

Il peut y avoir différents liens dans one 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>

remplacer:

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

mes idées (mais ne savent pas comment créer une déclaration pour eux):

  • où se trouvent les 100 caractères précédents "mydomain.de
  • où nombre de ".html" trouve = nombre de "mydomain.de" trouvé

Il n'a pas à être 100% correspondant à tous "mydomain.de" les liens, je suis heureux avec 90%, mais il ne devrait pas y avoir un remplacement erroné dans les liens externes.

3
demandé sur Andrea Schmuttermair 2016-07-23 15:42:22

4 réponses

mise à JOUR: Ont décidé d'en faire un billet de blog: http://stevettt.blogspot.co.uk/2018/02/a-mysql-regular-expression-replace.html


s'il vous Plaît voir la suite Rextester Violon, qui, je pense, devrait produire tous les résultats vous ont demandé:

Rextester Démo

explication

une fonction de remplacement de modèle est nécessaire pour cela, mais malheureusement MySQL ne fournit pas une telle chose . Donc j'en ai écrit un (basé sur un autre qui n'était pas tout à fait suffisant) et je l'ai posté ici . Comme mentionné dans la réponse référencée, cette fonction a une limitation de ne pas permettre la substitution de groupes de capture avec des références arrières. Il a donc été légèrement adapté dans le violon pour prendre d'autres paramètres qui lui permettent de effectuer un remplacement récursif dans la correspondance trouvée pour le remplacement. (Notez l'utilisation des caractères de chemin D'URL autorisés dans le regex selon cette excellente réponse ).

mise à Jour SQL

le SQL suivant mettra à jour les données de la table en utilisant la fonction ci-dessous:

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
  );

code de fonction

le code UDF utilisé dans la démo est aussi posté ci-dessous. Note: L'UDF délègue à une procédure stockée depuis seulement les procédures stockées permettront la récursion dans 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 ;
2
répondu Steve Chambers 2018-02-14 11:16:14

est-ce que ça fait ce que tu veux?

UPDATE tablename 
    SET contentfield = REPLACE(contentfield, '.html', '/') 
    WHERE contentfield like 'www.mydomain.de/%';

cela devrait fonctionner pour les exemples dans la question.

Si vous le souhaitez, vous pouvez utiliser la condition corresponde uniquement les lignes qui ont réellement ".code html".

    WHERE contentfield like 'www.mydomain.de/%.html%'
2
répondu Gordon Linoff 2016-07-23 12:44:33

je voudrais juste exporter la table à CSV ou quelque chose, puis utilisé notepad++/excel/etc. outil interne pour remplacer

'.html' avec un '/'.

et ensuite importer de nouveau à SQL.

aussi, puisque mysql supporte les expressions régulières, vous pouvez rechercher votre domaine, contenant .html avec elle.

 mydomain.de[^s]+.html
1
répondu Maksim.T 2016-07-29 11:40:55

vous pouvez utiliser comme

 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
répondu scaisEdge 2016-07-23 12:54:05