Oracle
 sql >> Database >  >> RDS >> Oracle

Come sfuggire a un regexp_replace in Oracle?

Dovrebbe funzionare a condizione che tu non abbia un input simile a %ABC#%ABC#

SELECT REGEXP_REPLACE( '%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX' )
FROM DUAL;

Questo corrisponderà a:

  • L'inizio della stringa ^ o un carattere non barra [^\] seguito da un numero qualsiasi di coppie di caratteri barra quindi, infine, i caratteri %ABC# . Questo corrisponderà a %ABC# , \\%ABC# , \\\\%ABC# e così via, ma non corrisponderà a \%ABC# , \\\%ABC# , \\\\\%ABC# dove è presente una barra che esegue l'escape del % carattere.

La sostituzione include il primo gruppo di acquisizione poiché l'espressione può corrispondere a un carattere non barra precedente e coppie di barre e queste devono essere conservate nell'output.

Aggiorna

Questo diventa un po' complicato ma farà corrispondenze ripetute:

WITH Data ( VALUE ) AS (
  SELECT '%ABC#%ABC#' FROM DUAL
)
SELECT ( SELECT LISTAGG(
                  REGEXP_REPLACE( COLUMN_VALUE, '((^|[^\])(\\\\)*)%ABC#$', '\1XXX' ),
                  NULL
                ) WITHIN GROUP ( ORDER BY NULL )
         FROM   TABLE(
                  CAST(
                    MULTISET(
                      SELECT  REGEXP_SUBSTR( d.value, '.*?(%ABC#|$)', 1, LEVEL )
                      FROM    DUAL
                      CONNECT BY LEVEL < REGEXP_COUNT( d.value, '.*?(%ABC#|$)' )
                    AS SYS.ODCIVARCHAR2LIST
                  )
                )
       ) AS Value
FROM   Data d;

Utilizza una sottoquery correlata per dividere la stringa in sottostringhe che terminano con %ABC# o la fine della stringa (questo è il bit all'interno di TABLE( CAST( MULTISET( ) .. ) ) ) e quindi riconcatena queste sottostringhe dopo aver eseguito la sostituzione alla fine di ciascuna sottostringa.