[英]Why does Ruby gsub not replace a second occurrence of this pattern?
我有一些代码可以将可能包含预转义引号的字符串中的双引号转义; 例如:
This is a \"string"
在Ruby 1.8.7p374中使用以下代码:
string.gsub!(/([^\\])"/, '\1\"')
但是,在以下字符串上尝试时会遇到一些有趣的边缘情况: ab""c
=> ab\\""c
。 我希望它能同时引用两个引号。
绝对不是什么大问题,但这让我感到好奇。
我的表达方式有误吗? gsub
错误/功能?
(在较新的Ruby版本中,可以使用否定的回溯轻松解决此问题,但此版本似乎不支持它们)。
要求匹配非\\
字符意味着正则表达式需要使用该字符以及引号。 gsub
匹配也不能重叠。
您认为后置断言可以解决此问题是正确的。 但是,如果没有可用的功能,Ruby 1.8.7中有两个选择。
重复直到没有替换为止(如果没有匹配项, gsub!
返回nil
):
loop { break unless string.gsub!(/([^\\\\])"/, '\\1\\"') }
对于1.8.7,您没有后置断言。 但是您可以反转字符串,使用先行断言进行更改,然后将其反转:
string = string.reverse.gsub(/"(?!\\\\)/, '"\\\\').reverse
如果字符串开头有引号,则您的正则表达式也将不起作用,例如"ab""c
将转换为"ab\\""c
。 原因与您使用双引号的情况类似。
gsub
匹配了b"
并将其替换后,它将从最后一个匹配继续,查看下一个"
,但不查看先前使用的字符。
在较新的Ruby版本中,您可以通过回溯来解决问题,但这不能解决字符串问题的开头。 解决该问题的方法是使用\\G
锚 (在Ruby 1.8.7中可用),该锚与上一个匹配项的结束位置或字符串的开头相匹配。 所以,你正在寻找一个"
要么是后一个非斜线或者是在当前比赛开始(意思是"
刚刚被匹配或这是字符串的开始)。 像这样:
string.gsub!(/([^\\]|\G)"/, '\1\"')
这会将字符串"ab""c
转换为\\"ab\\"\\"c
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.