[英]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.