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

Dmy*_*iak 9 ruby regex ruby-on-rails gsub

s = "#main= 'quotes'
s.gsub "'", "\\'" # => "#main= quotes'quotes"
Run Code Online (Sandbox Code Playgroud)

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

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

s.gsub "'", "*" # => "#main= *quotes*"
Run Code Online (Sandbox Code Playgroud)

所以必须与逃避有关.

使用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)
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

mu *_*ort 17

你正在被\'正则表达式替换字符串中的特殊性绊倒:

\0,\1,\2,... \9,\&,\`,\',\+
替代由第n个分组的子表达式匹配的值,或通过在整场比赛,前或postmatch,或最高的组.

所以当你说"\\'",double \\只是一个反斜杠而结果是,\'但这意味着"上一次成功匹配右边的字符串".如果要使用转义单引号替换单引号,则需要转义更多以超越以下特殊性\':

s.gsub("'", "\\\\'")
Run Code Online (Sandbox Code Playgroud)

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

s.gsub("'") { |m| '\\' + m }
Run Code Online (Sandbox Code Playgroud)

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

这里的总体教训是更喜欢除了最微不足道的替换之外的任何阻止形式gsub.