Detta bör fungera förutsatt att du inte har en ingång som ser ut som %ABC#%ABC#
SELECT REGEXP_REPLACE( '%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX' )
FROM DUAL;
Detta kommer antingen att matcha:
- Starten av strängen
^
eller ett snedstreck[^\]
följt av valfritt antal par av snedstreck tecken sedan, slutligen, tecknen%ABC#
. Detta kommer att matcha%ABC#
,\\%ABC#
,\\\\%ABC#
och så vidare men kommer inte att matcha\%ABC#
,\\\%ABC#
,\\\\\%ABC#
där det finns ett snedstreck som undkommer%
tecken.
Ersättningen inkluderar den första fångstgruppen eftersom uttrycket kan matcha ett föregående tecken utan snedstreck och par av snedstreck och dessa måste bevaras i utdata.
Uppdatera
Det här blir lite komplicerat men det kommer att göra upprepade matchningar:
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;
Den använder en korrelerad underfråga för att dela upp strängen i understrängar som slutar med %ABC#
eller slutet av strängen (detta är biten inuti TABLE( CAST( MULTISET( ) .. ) )
) och sammanfogar sedan dessa understrängar igen efter att ha utfört ersättningen i slutet av varje understräng.