这应该工作只要你没有看起来的输入像%ABC#%ABC#
SELECT REGEXP_REPLACE('%ABC#abc\%ABC#', '((^|[^\])(\\\\)*)%ABC#', '\1XXX')
FROM DUAL;
这既会匹配:
字符串^或非斜杠字符的开始[^\]然后是任意数量的斜杠字符对,最后是字符%ABC#。这将匹配%ABC#,\\%ABC#,\\\\%ABC#等等,但将不匹配\%ABC#,\\\%ABC#,\\\\\%ABC#,其中有一个斜杠转义%字符。
替换包括第一个捕获组,因为表达式可以匹配前面的非斜杠字符和斜杠对,并且这些需要保留在输出中。
更新
这变得有点复杂,但它会反复做匹配:
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;
它使用了相关子查询字符串分割成最终的子串与%ABC#或字符串的结尾(这是TABLE(CAST(MULTISET() ..))中的位),然后在每个子字符串的末尾执行替换之后重新连接这些子字符串。