如何在Oracle中转义regexp_替换?

如何在Oracle中转义regexp_替换?,regex,oracle,Regex,Oracle,我正在为字符串创建一个小的replaceParam函数,并希望能够转义替换,例如。g select regexp_replace('%ABC# %ABC#','%ABC#', 'XXX') from dual; 导致 XXX XXX 但我希望能够逃脱重播,e。G通过在字符串前面加上\,该字符串将被替换 select regexp_replace('%ABC# \%ABC#','<themagicregexp>', 'XXX') from dual; 我尝试了不匹配的字符列表,但

我正在为字符串创建一个小的replaceParam函数,并希望能够转义替换,例如。g

select regexp_replace('%ABC# %ABC#','%ABC#', 'XXX')
from dual;
导致

XXX XXX
但我希望能够逃脱重播,e。G通过在字符串前面加上\,该字符串将被替换

select regexp_replace('%ABC# \%ABC#','<themagicregexp>', 'XXX')
from dual;
我尝试了不匹配的字符列表,但这不起作用

select regexp_replace('%ABC#abc\%ABC#','<themagicregexp>', 'XXX')
from dual;
此外,因为有人提到了这一点:我不能使用单词边界,因为这也应该适用:

yoyo%ABC#yoyo

我觉得这可以在一个regexp中完成,但我看不到它?

如果您没有类似于%ABC%ABC的输入,这应该可以工作

这将匹配:

字符串^或非斜杠字符[^\]的开头,后跟任意数量的斜杠字符对,最后是字符%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或字符串结尾的子字符串这是表CAST MULTISET中的位。。然后在每个子字符串的末尾执行替换后重新连接这些子字符串。

我喜欢一种更简单的方法:

select replace(
         regexp_replace(
           replace('%ABC# \%ABC#','\%','~~')
           ,'%ABC#', 'XXX')
         ,'~~','\%')
from dual;
但是,请注意,在这种特殊情况下不需要正则表达式-这同样适用:

select replace(
         replace(
           replace('%ABC# \%ABC#','\%','~~')
           ,'%ABC#', 'XXX')
         ,'~~','\%')
from dual;

如果您的输入看起来像“%ABC\\%ABC”,会发生什么情况?您是想让我了解我的想法中存在的设计缺陷,还是您的问题的目的是什么?目前的结果是XXX\\XXX,因为我没有以任何工作方式逃跑。我试图弄清楚在这种边缘情况下你会发生什么。解决方案的行为仍应针对该情况进行定义,因为永远不会有这样的输入,这不是一个好的假设。我希望出现以下情况:XXX\\%ABC,但我应该检查此边缘情况。谢谢你的提示!这很有效,谢谢。我仍然要弄清楚原因,但这很有帮助!编辑:你第一次帮助我掌握了反向引用…@bitschnau对正则表达式的解释补充道。\\\*部分介绍@Tomalak对您的问题的评论。为什么%ABC%ABC没有替换为XXXXXX,因为在我看来,如果在继续查找更多模式之前替换第一个出现的字符,那么非反斜杠字符是否与X类似?它将在第一个匹配之后开始查找重复的匹配,但由于它不在字符串的开头,它无法匹配^%ABC,必须匹配非斜杠字符,然后是%ABC-因此它将匹配第一个实例,但不能匹配紧接其后的第二个实例。@bitschnau使用一个将处理连续匹配的查询进行了更新,但这不是一个简单的解决方案。%ABC~~%ABC在应为XXX~~~XXX时转到XXX\%XXX,而\\%ABC在应为\\XXX时转到\\%ABC。@MT0这只是一个示例-您可以使用一个替换字符串不会出现在真实文本中。我只是以~~为例。此外,q从未指定任何关于“\\”的特殊内容,但如果必要,也可以使用相同的技术轻松替换。注释中澄清了\、\\、\。你能举个例子说明如何容易地替换它吗?你可以使用replace函数来替换它们。此外,在100%的情况下,您也不会对它的工作过于挑剔——只是您的应用程序需要满足的情况范围:
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;
select replace(
         regexp_replace(
           replace('%ABC# \%ABC#','\%','~~')
           ,'%ABC#', 'XXX')
         ,'~~','\%')
from dual;
select replace(
         replace(
           replace('%ABC# \%ABC#','\%','~~')
           ,'%ABC#', 'XXX')
         ,'~~','\%')
from dual;