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

Zar*_*doz 6 ruby regex

如何在捕获的组之前跳过反斜杠?

例:

"foo+bar".gsub(/(\+)/, '\\\1')
Run Code Online (Sandbox Code Playgroud)

我期望(和想要):

foo\+bar
Run Code Online (Sandbox Code Playgroud)

我不幸得到的:

foo\\1bar
Run Code Online (Sandbox Code Playgroud)

我该如何正确逃离?

evn*_*nkm 7

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

原因是替换序列被解析两次 - 一次是Ruby,一次是底层正则表达式引擎,对象\1是自己的转义序列.(它可能更容易与双引号字符串理解,因为单引号引进的不确定性,其中'\\1''\1'是等价的,但'\''\\'没有.)

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

"foo+bar".gsub(/(\+)/, "\\1")   #=> "foo+bar"
Run Code Online (Sandbox Code Playgroud)

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

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

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

附录

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

Regexp.new("\.").match("a")   #=> #<MatchData "a">
Regexp.new("\\.").match("a")  #=> nil
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我们必须要仔细逃脱.它被理解为文字.由正则表达式引擎,因为".""\."这两个评估以.在双引号字符串,但我们需要发动机本身接收\..