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

妖精的绣舞 提交于 2019-12-02 06:24:36

问题


I have this string:

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

that is a part of the html content of my record.

Now, my problem is that I tried to replace ONLY the '+' in the href tags, so I create in MySQL this script:

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)
                        ),
                    '+',
                    ' ')
                );

where @xxx is the string in question. The head is <a href and the tail is </a>, and this never change.

But I obtain this result, with a changing only in the substrings that are the same of the first, because the script search only other substrings with the same central part :

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

I must replace all the '+' in the href tags WITHOUT replacing the '+' in the other places, like in '€ 400+IVA' or in 'al numero +39.00.0.0.0.00.' .

Thank you for the help in advance, I hope the question is not so cryptic ^^ .


回答1:


it's possible in pure MySQL only without the use off a full blown HTML parser or a UDF that would import REGEX_REPLACE function into MySQL.

The trick is by using a number generator and by using a nested SUBSTRING_INDEX to split the large string on the html tags
This number generator will generate number from 1 to 10.000
So the "parser" will support up to 10.000 tags if you need more you need to add more

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]

Query

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

this SQL statement will be used to split on html tag

SQL statement

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

The trick now is to combine the number generator and the html string splittig. So the [tag_position] is filled with a number from the number generator.
This is done with a CROSS JOIN.

Query

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 != '>'

see demo http://www.sqlfiddle.com/#!9/de2ed/32

Now we have the tags as separated records it really eazy to replace only with in records that contain "href".

SQL statement

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

see demo http://www.sqlfiddle.com/#!9/de2ed/38

Now that we know how to replace now we are going to merge the records back to one string. We can use GROUP_CONCAT for that.

Query

    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 != '>'

see demo for the complete query

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



来源:https://stackoverflow.com/questions/49560296/mysql-replace-how-replace-all-occurrences-of-a-char-in-every-distinct-substrin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!