为什么String#gsub会双重内容?

时间:2011-08-16 06:24:34

标签: ruby-on-rails ruby regex gsub

s = "#main= 'quotes'
s.gsub "'", "\\'" # => "#main= quotes'quotes"

这似乎是错误的,我希望得到"#main= \\'quotes\\'"

当我不使用转义字符时,它按预期工作。

s.gsub "'", "*" # => "#main= *quotes*"

因此必须与逃避有关。

使用ruby 1.9.2p290

我需要用反斜杠和引号替换单引号。

更加不一致:

"\\'".length # => 2
"\\*".length # => 2

# As expected
"'".gsub("'", "\\*").length # => 2
"'a'".gsub("'", "\\*") # => "\\*a\\*" (length==5)

# WTF next:
"'".gsub("'", "\\'").length # => 0

# Doubling the content?
"'a'".gsub("'", "\\'") # => "a'a" (length==3)

这里发生了什么?

3 个答案:

答案 0 :(得分:17)

你被\' inside a regular expression replacement string的特殊性绊倒了:

  

\0\1\2,... \9\&\`\'\+
  替换第n个分组子表达式匹配的值,或者整个匹配,匹配前或匹配后或最高组。

因此,当您说"\\'"时,双\\只会变为一个反斜杠,结果为\',但这意味着“上一次成功匹配右侧的字符串”。如果您想要使用转义单引号替换单引号,则需要转义更多以超越\'的特殊性:

s.gsub("'", "\\\\'")

或者避免使用牙签并使用阻止形式:

s.gsub("'") { |m| '\\' + m }

如果你试图逃避反引号,加号,甚至是一个数字,你会遇到类似的问题。

这里的总体教训是,除了最微不足道的替换外,我更喜欢block form of gsub

答案 1 :(得分:2)

s = "#main = 'quotes'

s.gsub "'", "\\\\'"

由于\它是\\等效的,如果你想得到一个双反斜杠,你必须放四个。

答案 2 :(得分:1)

您还需要逃避\:

s.gsub "'", "\\\\'"

输出

"#main= \\'quotes\\'"

在外部论坛上发现一个很好的解释:

  

理解恕我直言的关键是反斜杠是特别的   替换字符串。所以,每当有人想要一个文字时   替换字符串中的反斜杠需要逃避它,因此   有[两个]反斜杠。巧合的是,反斜杠在a中也很特别   字符串(即使在单引号字符串中)。所以你需要两个级别   转义,在屏幕上为一个文字制作2 * 2 = 4个反斜杠   替换反斜杠。

source