To powinno działać, pod warunkiem, że nie masz danych wejściowych, które wyglądają jak %ABC#%ABC#
SELECT REGEXP_REPLACE( '%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX' )
FROM DUAL;
To będzie pasować:
- Początek ciągu
^
lub znak inny niż ukośnik[^\]
po którym następuje dowolna liczba par znaków ukośnika, a na końcu znaki%ABC#
. To będzie pasować do%ABC#
,\\%ABC#
,\\\\%ABC#
i tak dalej, ale nie pasuje do\%ABC#
,\\\%ABC#
,\\\\\%ABC#
gdzie jest ukośnik poprzedzający%
postać.
Zastąpienie obejmuje pierwszą grupę przechwytywania, ponieważ wyrażenie może pasować do poprzedzającego znaku bez ukośnika i par ukośników, które muszą być zachowane w danych wyjściowych.
Aktualizacja
To trochę się komplikuje, ale spowoduje powtarzające się dopasowania:
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;
Używa skorelowanego podzapytania, aby podzielić ciąg na podciągi, które kończą się %ABC#
lub koniec ciągu (jest to bit wewnątrz TABLE( CAST( MULTISET( ) .. ) )
), a następnie ponownie łączy te podciągi po wykonaniu zamiany na końcu każdego podciągu.