[英]Ruby gsub regex unexpected behaviour
我以为我很了解正则表达式,但这令我困惑:
irb(main):016:0> source = "/foo/bar"
=> "/foo/bar"
irb(main):017:0> source.gsub( /[^\/]*\Z/, "fubar" )
=> "/foo/fubarfubar"
据我所知, /[^\\/]*\\Z/
有一个匹配bar
的唯一扩展,因此应该导致/foo/fubar
。 我根本看不出为什么我把fubarfubar
作为替代品。
如果我调用sub
而不是gsub
,替换工作,所以这不是解决问题的问题,而是揭示我对gsub
误解。
你需要使用sub
因为你只需要在字符串的末尾替换一次:
source.sub( /[^\/]*\Z/, "fubar" )
^^^
请参阅IDEONE演示
问题很可能与收集匹配的方式有关,并且由于模式匹配空字符串,尽管最后,最后一个null也可以被视为第二个匹配。 它不仅是一个Ruby问题,许多其他语言中也存在类似的错误。
所以,实际上,这就是发生的事情:
[^\\/]*\\Z
模式匹配bar
并用foobar
替换它 [^\\/]*\\Z
匹配NULL,并添加另一个foobar
。 如果你需要使用gsub
,替换*
量字,允许匹配0个字符+
需要至少出现1次量化子模式,避免匹配0长度字符串:
source.gsub( /[^\/]+\Z/, "fubar" )
^
经验法则 :避免在Regex替换方法中匹配空字符串的正则表达式!
我认为这根本不是一个错误。 正则表达式可以并且将匹配零宽度位置。
因此,正则表达式引擎看到字符串"xox"
更像这样:
"" "x" "" "o" "" "x" ""
(有趣的事实:在Ruby中,上面实际上导致"xox"
)
如果我们gsub
一个x
与_
,一切都按预期工作:
"xox".gsub(/x/, "_") #=> "_o_"
但如果我们匹配x*
,事情会变得奇怪:
"xox".gsub(/x*/, "_") #=> "__o__"
这是因为*
匹配零次或多次:
"" "x" "" "o" "" "x" ""
^^^^^^ ^^ ^^^^^^ ^^
如果我们将“零或更多”减少到零,可能会更清楚:
"xox".gsub(/x{0}/, "_") #=> "_x_o_x_"
比赛是:
"" "x" "" "o" "" "x" ""
^^ ^^ ^^ ^^
你的例子也是如此。 您匹配[^\\/]
零次或多次。 正则表达式引擎匹配字符串末尾的bar
( [^\\/]
3次)和之后的void( [^\\/]
0次):
"/" "" "b" "" "a" "" "r" ""
^^^^^^^^^^^^^^^^^^^^ ^^
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.