MySQL REPLACE :如何替换每个不同子字符串中所有出现的字符,这些子字符串由相同的头尾分隔

MySQL REPLACE : How replace all occurrences of a char in every distinct substring delimited by the same head and tail

我有这个字符串:

<p><span><b>C10373 - FIAT GROUP AUTOMOBILES/RAMO DI AZIENDA DI KUEHNE + NAGEL</b></span>
<p>la somma pari a € 400+IVA per l’attività</p>
<p>TELE+ A 20.000 LIRE AL MESE </p>
<li>a mano o via fax al numero +39.00.0.0.0.00.</li>
<p>Il punteggio base sarà incrementato di un <strong>+ </strong>al ricorrere di ciascuna delle seguenti condizioni:</p>
<li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D+RDO_1560277Lettera_Invito.pdf" title="">Lettera di invito</a></li>
<li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+disciplinare+di+gara-signed.pdf" title="">Disciplinare di gara</a></li>
<li><a href="/aaa/gare/CIGZB81E5568D+determina+di+aggiudicazione+58+2017.pdf" title="">Determina di aggiudicazione</a></li>

这是我记录的 html 内容的一部分。

现在,我的问题是我试图仅替换 href 标签中的“+”,所以我在 MySQL 中创建了这个脚本:

set @xxx = replace(
                @xxx,
                substr(@xxx,locate('<a href',@xxx)+3,locate('</a>',@xxx)-locate('<a href',@xxx)),
                replace(
                    substr(
                            @xxx, 
                            locate('<a href',@xxx)+3,
                            locate('</a>',@xxx)-locate('<a href',@xxx)
                        ),
                    '+',
                    ' ')
                );

@xxx 是有问题的字符串。 头是<a href,尾是</a>,这永远不会改变。

但我得到了这个结果,只改变了与第一个相同的子串,因为脚本只搜索具有相同中心部分的其他子串:

<p><span><b>C10373 - FIAT GROUP AUTOMOBILES/RAMO DI AZIENDA DI KUEHNE + NAGEL</b></span>
<p>la somma pari a € 400+IVA per l’attività</p>
<p>TELE+ A 20.000 LIRE AL MESE </p>
<li>a mano o via fax al numero +39.06.85.82.12.56.</li>
<p>Il punteggio base sarà incrementato di un <strong>+ </strong>al ricorrere di ciascuna delle seguenti condizioni:</p>
<li><a href="/aaa/gare/CIGZB81E5568D RDO1560277 Obblighi contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D RDO1560277 Obblighi contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D+RDO_1560277Lettera_Invito.pdf" title="">Lettera di invito</a></li>
<li><a href="/aaa/gare/CIGZB81E5568D RDO1560277 Obblighi contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
<li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+disciplinare+di+gara-signed.pdf" title="">Disciplinare di gara</a></li>
<li><a href="/aaa/gare/CIGZB81E5568D+determina+di+aggiudicazione+58+2017.pdf" title="">Determina di aggiudicazione</a></li>

我必须替换 href 标签中的所有“+”,而不替换其他地方的“+”,例如“€ 400+IVA”或 'al numero +39.00.0.0.0.00.'。

先谢谢大家的帮助,希望问题不要那么晦涩^^ .

仅在不使用完整的 HTML 解析器或将 REGEX_REPLACE 函数导入 MySQL 的 UDF 的情况下,在纯 MySQL 中才有可能。

诀窍是使用数字生成器并使用嵌套 SUBSTRING_INDEX 拆分 html 标签上的大字符串
此数字生成器将生成从 1 到 10.000 的数字
所以 "parser" 将支持多达 10.000 个标签,如果你需要更多,你需要添加更多

CROSS JOIN (
     SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
    ) AS record_[number]

查询

SELECT 
 (@number := @number + 1) AS number
FROM (    
  SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN (
  SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_2
CROSS JOIN (
 SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_3
CROSS JOIN (
  SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_4
CROSS JOIN ( SELECT @number := 0 ) AS init_user_param

此 SQL 语句将用于拆分 html 标签

SQL声明

CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX([large_html_string], ">", [tag_position]), ">", -1), ">") as tag 

现在的技​​巧是结合数字生成器和 html 字符串拆分。因此 [tag_position] 中填充了来自数字生成器的数字。
这是通过 CROSS JOIN 完成的。

查询

SELECT 
 *
FROM ( 

  SELECT 
    CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX(data, ">", generator.number), ">", -1), ">") as tag 
  FROM (

    SELECT '<p><span><b>C10373 - FIAT GROUP AUTOMOBILES/RAMO DI AZIENDA DI KUEHNE + NAGEL</b></span>
    <p>la somma pari a € 400+IVA per l’attività</p>
    <p>TELE+ A 20.000 LIRE AL MESE </p>
    <li>a mano o via fax al numero +39.00.0.0.0.00.</li>
    <p>Il punteggio base sarà incrementato di un <strong>+ </strong>al ricorrere di ciascuna delle seguenti condizioni:</p>
    <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
    <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
    <li><a href="/aaa/gare/CIGZB81E5568D+RDO_1560277Lettera_Invito.pdf" title="">Lettera di invito</a></li>
    <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
    <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+disciplinare+di+gara-signed.pdf" title="">Disciplinare di gara</a></li>
    <li><a href="/aaa/gare/CIGZB81E5568D+determina+di+aggiudicazione+58+2017.pdf" title="">Determina di aggiudicazione</a></li>' AS data

   ) AS record 
   CROSS JOIN (
     SELECT 
       (@number := @number + 1) AS number
     FROM (    
       SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
     ) AS record_1
     CROSS JOIN (
       SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
     ) AS record_2
     CROSS JOIN (
       SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
     ) AS record_3
     CROSS JOIN (
       SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
     ) AS record_4
     CROSS JOIN ( SELECT @number := 0 ) AS init_user_param
   ) 
    AS generator
 ) 
 AS tags
WHERE 
 tags.tag != '>'

观看演示 ​​http://www.sqlfiddle.com/#!9/de2ed/32

现在我们将标签作为单独的记录,只用包含 "href" 的记录替换它真的很容易。

SQL 声明

 (
    CASE 
      WHEN 
        LOCATE("href", tags.tag) > 0
      THEN 
        REPLACE(tags.tag, "+", " ") 
      ELSE 
        tags.tag
    END
 ) AS tag

查看演示 http://www.sqlfiddle.com/#!9/de2ed/38

现在我们知道如何替换了,现在我们要把记录合并回一个字符串。为此,我们可以使用 GROUP_CONCAT。

查询

    SET SESSION group_concat_max_len = @@max_allowed_packet;

    SELECT 
     GROUP_CONCAT(
        CASE 
          WHEN 
            LOCATE("href", tags.tag) > 0
          THEN 
            REPLACE(tags.tag, "+", " ") 
          ELSE 
            tags.tag
        END
       SEPARATOR ""
     ) AS html

    FROM ( 

      SELECT 
        CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX(data, ">", generator.number), ">", -1), ">") as tag 
      FROM (

        SELECT '<p><span><b>C10373 - FIAT GROUP AUTOMOBILES/RAMO DI AZIENDA DI KUEHNE + NAGEL</b></span>
        <p>la somma pari a € 400+IVA per l’attività</p>
        <p>TELE+ A 20.000 LIRE AL MESE </p>
        <li>a mano o via fax al numero +39.00.0.0.0.00.</li>
        <p>Il punteggio base sarà incrementato di un <strong>+ </strong>al ricorrere di ciascuna delle seguenti condizioni:</p>
        <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
        <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
        <li><a href="/aaa/gare/CIGZB81E5568D+RDO_1560277Lettera_Invito.pdf" title="">Lettera di invito</a></li>
        <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+Obblighi+contattuali-signed.pdf" title="">Obblighi contrattuali</a></li> 
        <li><a href="/aaa/gare/CIGZB81E5568D+RDO1560277+disciplinare+di+gara-signed.pdf" title="">Disciplinare di gara</a></li>
        <li><a href="/aaa/gare/CIGZB81E5568D+determina+di+aggiudicazione+58+2017.pdf" title="">Determina di aggiudicazione</a></li>' AS data

       ) AS record 
       CROSS JOIN (
         SELECT 
           (@number := @number + 1) AS number
         FROM (    
           SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
         ) AS record_1
         CROSS JOIN (
           SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
         ) AS record_2
         CROSS JOIN (
           SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
         ) AS record_3
         CROSS JOIN (
           SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
         ) AS record_4
         CROSS JOIN ( SELECT @number := 0 ) AS init_user_param
       ) 
        AS generator
     ) 
     AS tags
    WHERE 
     tags.tag != '>'

查看完整查询演示

http://www.sqlfiddle.com/#!9/de2ed/46