2016-02-12 20 views
2

我正在为Strings创建一个小的replaceParam函数,并希望能够逃避替换, G。如何在Oracle中转义regexp_replace?

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

导致

XXX XXX 

但我希望能够逃脱replacment,E。 G。通过在字符串前面加一个\,否则将被替换。

select regexp_replace('%ABC# \%ABC#','<themagicregexp>', 'XXX') 
from dual; 

应导致

XXX \%ABC# 

我尝试了不匹配的字符列表,但这不起作用。

select regexp_replace('%ABC#abc\%ABC#','<themagicregexp>', 'XXX') 
from dual; 

应导致

XXXabc\%ABC# 

此外,因为有人提到它:我不能跟字边界去,因为这也应该工作:

yoyo%ABC#yoyo 

我有感觉这可以在一个正则表达式中完成,但我只是看不到它?

+0

如果你的输入会发生什么看起来像''%ABC#\\%ABC#''? – Tomalak

+0

您是否试图将我引入我的想法的设计缺陷或您的问题的目的是什么? 目前的结果是XXX \\ XXX,因为我不会以任何工作方式逃脱。 – bl4ckb0l7

+2

我试图找出你期望在这种边缘情况下会发生什么。对于这种情况,解决方案的行为仍应该定义,因为“永远不会有这样的输入”不是一个好的假设。 – Tomalak

回答

3

这应该工作只要你没有看起来的输入像%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() ..))中的位),然后在每个子字符串的末尾执行替换之后重新连接这些子字符串。

+0

这工作,谢谢。我仍然必须弄清楚为什么,但它有很大帮助!编辑:你帮我第一次掌握反向引用... – bl4ckb0l7

+1

@bitschnau添加正则表达式的解释。 '(\\\\)*'部分针对您的问题解决了@Tomalak的评论。 – MT0

+0

为什么%ABC#%ABC#没有被替换为XXXXXX,因为如果在继续并寻找更多模式之前替换第一个匹配项,那么#对我来说就像是一个非反斜杠字符? – bl4ckb0l7

2

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

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

但是请注意,在这种特定的情况下,不需要正则表达式 - 该作品一样好:

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

'%ABC#~~%ABC#'当它应该是'XXX ~~ XXX'并且'\\%ABC#'应该转到'\\%ABC#'时,它会转到'XXX \%XXX'到'\\ XXX'。 – MT0

+0

@ MT0这只是一个例子 - 你会使用一个永远不会出现在真实文本中的替换字符串。我只是以'~~'为例。此外,q从未指定任何关于'\\\'的特殊内容,但如果需要,也可以使用相同的技术轻松替换。 –

+0

在评论中澄清了'\\','\\\\','\\\\\'。你能举一个例子说明它如何“容易”被替换? – MT0