在regexp_replace

时间:2016-11-10 20:59:45

标签: regex postgresql

我偶然发现了regexp_replace PostgreSQL函数的奇怪行为。它看起来像一个bug但我总是怀疑自己。我跑的时候

SELECT regexp_replace(E'1%2_3', '([_%])', E'\\ \\1', 'g')

它正确地用反斜杠或空格作为下划线或百分比的前缀,并产生“1\ %2\ _3”。但是,当我删除空格(它不必是空格,可以是任何字符)

SELECT regexp_replace(E'1%2_3', '([_%])', E'\\\\1', 'g')

它会在替换中停止使用捕获的带括号的表达式,并生成“1\12\13”而不是“1\%2\_3”。如果有人能告诉我我做错了什么,我将不胜感激。我只需要在字符串中的某些字符之前添加反斜杠。

更新:我可以通过运行

来实现所需的行为
SELECT regexp_replace(E'1%2_3', '([_%])', E'\\\\\\1', 'g')

我的原始例子似乎仍然有点不合逻辑且不一致。不一致是使用相同的E'...'语法4反斜杠可能会产生不同的结果。

2 个答案:

答案 0 :(得分:1)

在第二个查询中,在字符串级别处理反斜杠转义后,您将拥有替换字符串\\1

发生的事情是,转义的反斜杠会阻止\1被识别为反向引用。您需要另一组反斜杠,以便替换字符串\\\1以获取文字反斜杠和反向引用。由于每个字面反斜杠都需要进行转义,因此需要将它们全部加倍。

SELECT regexp_replace(E'1%2_3', '([_%])', E'\\\\\\1', 'g')

答案 1 :(得分:1)

我不会首先在Postgres中使用过时的Posix转义语法。您使用standard_conforming_strings = off运行过期版本吗?因为如果不是,请简化:

SELECT regexp_replace('1%2_3', '([_%])', '\\\1', 'g')

您只需添加一个\即可逃避正则表达式模式中\的特殊含义。

必须处理前缀为E的字符串,这需要额外的费用,并且始终存在使用特殊字符的意外副作用的风险。为{<1}}写一个你想要提供的字符串是没有意义的。在任何情况下都只需E'1%2_3'

仅用两个字符代替简单使用:

'1%2_3'

正则表达式很强大,但需要付出代价。即使是几个嵌套的简单SELECT replace(replace('1%2_3', '_', '\_'), '%', '\%') 调用也比单个replace()便宜。