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.