繁体   English   中英

Ruby gsub正则表达式出乎意料的行为

[英]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替换它
  • 正则表达式索引位于字符串的末尾 - 是的,有一个NULL,但Ruby仍然认为它是一个有效的“字符串”来处理和
  • [^\\/]*\\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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM