簡體   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