我正在尝试使用Ruby中的&
替换\&
字符串中的每个String#gsub
。我所看到的让我困惑,因为我希望得到milk \& honey
:
irb(main):009:0> puts "milk & honey".sub(/&/,'\ &')
milk \ & honey
=> nil
irb(main):010:0> puts "milk & honey".sub(/&/,'\&')
milk & honey
=> nil
irb(main):011:0> puts "milk & honey".sub(/&/,'\\&')
milk & honey
=> nil
irb(main):012:0>
这是在OS X上的Ruby 2.0.0p481上。(我之前使用的是String#sub
,但计划在字符串中使用String#gsub
来处理一个以上&
的一般情况。 )
答案 0 :(得分:5)
当您将字符串作为替换值传递给String#sub
(或String#gsub
)时,会首先扫描后向引用到原始字符串。这里特别感兴趣的是,序列\&
被匹配整个正则表达式的字符串的任何部分所取代:
puts "bar".gsub(/./, '\\&\\&') # => bbaarr
请注意,尽管有外观,但Ruby字符串文字'\\&\\&'
表示只包含四个字符的字符串,而不是六个字符:
puts '\\&\\&' # => \&\&
这是因为即使是单引号的Ruby字符串也会受到反斜杠替换,以便在单引号字符串中包含单引号。只有'
或另一个反斜杠本身会触发替换;反斜杠后跟其他任何东西都只是一个字面反斜杠。这意味着您通常可以获得文字反斜杠而不会加倍:
puts '\&\&' # still => \&\&
但这是一个依赖的细节,因为下一个角色可能会改变解释。最安全的做法是将所有想要在字符串中出现的反斜杠加倍。
现在在这种情况下,我们希望以某种方式获得sub
的文字反斜杠 - &符号退出。幸运的是,就像Ruby字符串解析器一样,sub
允许我们使用加倍的反斜杠来指示反斜杠应该作为文字而不是反向引用的开头。我们只需要加倍sub
收到的字符串中的反斜杠 - 这意味着在字符串的文字表示中加倍两个的反斜杠,将这个形式的总共四个反斜杠带到:
puts "milk & honey".sub(/&/, '\\\\&')
如果你喜欢生活危险,你可以在这里只使用三个反斜杠。 :)
或者,您可以避免所有反斜杠计数并使用块形式,其中通过调用代码块而不是解析静态字符串来获取替换。由于块可以自由地进行任何类型的替换或字符串整理,因此它的返回值不会被扫描为字符串版本的反斜杠替换:
puts "milk & honey".sub(/&/) { '\\&' }
或“风险”版本:
puts "milk & honey".sub(/&/) { '\&' }
答案 1 :(得分:1)
只需\
:
puts "milk & honey".sub(/&/,'\\\&')
请参阅IDEONE demo
在Ruby正则表达式中,\&
表示整个正则表达式,这就是它应该被转义的原因,然后我们需要添加文字\
。下面列出了更多可用的模式:
\& (the entire regex)
\+ (the last group)
\` (pre-match string)
\' (post-match string)
\0 (same as \&)
\1 (first captured group)
\2 (second captured group)
\\ (a backslash)
块表示更容易,更易于阅读和维护:
puts "milk & honey".sub(/&/) { '\&' }