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.