To by mělo fungovat za předpokladu, že nemáte vstup, který vypadá jako %ABC#%ABC#
SELECT REGEXP_REPLACE( '%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX' )
FROM DUAL;
To bude buď odpovídat:
- Začátek řetězce
^
nebo znak[^\]
bez lomítka následovaný libovolným počtem dvojic lomítek a nakonec znaky%ABC#
. To bude odpovídat%ABC#
,\\%ABC#
,\\\\%ABC#
a tak dále, ale nebude odpovídat\%ABC#
,\\\%ABC#
,\\\\\%ABC#
kde je lomítko před%
postava.
Nahrazení zahrnuje první skupinu zachycení, protože výraz se může shodovat s předchozím nelomítkovým znakem a páry lomítek, které je třeba ve výstupu zachovat.
Aktualizovat
To bude trochu komplikované, ale bude to dělat opakované shody:
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;
Používá korelovaný poddotaz k rozdělení řetězce na podřetězce, které končí %ABC#
nebo konec řetězce (toto je bit uvnitř TABLE( CAST( MULTISET( ) .. ) )
) a poté tyto podřetězce znovu zřetězí po provedení nahrazení na konci každého podřetězce.