Ruby正则表达式中的反斜杠+捕获组

时间:2011-04-22 12:42:45

标签: ruby regex

如何在捕获的组之前触发反斜杠?

示例:

"foo+bar".gsub(/(\+)/, '\\\1')

我期望(和想要):

foo\+bar

我不幸得到了:

foo\\1bar

我如何正确逃离?

3 个答案:

答案 0 :(得分:7)

正如其他人所说,你需要两次逃脱该字符串中的所有内容。因此,在您的情况下,解决方案是使用'\\\\\1''\\\\\\1'。但既然你问为什么,我会试着解释那个部分。

原因是替换序列被解析两次 - 一次是Ruby,一次是底层正则表达式引擎,\1是它自己的转义序列。 (使用双引号字符串可能更容易理解,因为单引号引入了歧义,其中'\\1''\1'是等价的,但'\''\\'不是。)

因此,例如,此处使用捕获的组和双引号字符串进行简单替换将是:

"foo+bar".gsub(/(\+)/, "\\1")   #=> "foo+bar"

这将字符串\1传递给regexp引擎,它将其理解为对捕获组的引用。在Ruby字符串文字中,"\1"完全意味着其他东西(ASCII字符1)。

在这种情况下我们真正想要的是regexp引擎接收\\\1。它还将\理解为转义字符,因此\\1是不够的,只会评估为文字输出\1。因此,我们在regexp引擎中需要\\\1,但要达到这一点,我们还需要使它超过Ruby的字符串文字解析器。

为此,我们采用所需的正则表达式输入并再次加倍每个反斜杠以通过Ruby的字符串文字解析器。因此\\\1需要"\\\\\\1"。在单引号的情况下,可以省略一个斜杠,因为\1不是单引号中的有效转义序列,而是按字面处理。

附录

这个问题通常被隐藏的原因之一是由于使用了/.+/样式的正则表达式引用,Ruby以一种特殊的方式处理,以避免双重转义所有内容。 (当然,这不适用于gsub替换字符串。)但如果在Regexp.new中使用字符串文字而不是正则表达式字面值,您仍然可以看到它:

Regexp.new("\.").match("a")   #=> #<MatchData "a">
Regexp.new("\\.").match("a")  #=> nil

正如您所看到的那样,我们不得不双重转义.,因为."."所以regexp引擎将其理解为文字"\."两者都在双引号字符串中评估为.,但我们需要引擎本身才能接收\.

答案 1 :(得分:4)

这是由于双字符串转义而发生的。在这种情况下你应该使用5个斜杠。

"foo+bar".gsub(/([+])/, '\\\\\1')

答案 2 :(得分:2)

再添加\两次,可以正确地解决这个问题。

irb(main):011:0> puts "foo+bar".gsub(/(\+)/, '\\\\\1')
foo\+bar
=> nil