[英]Javascript - MultiLine RegExp: lastIndex stuck on newlines?
來自Javascript:The Definitive Guide :
但是,當
regexp
是全局正則表達式時,exec()
行為方式稍微復雜一些。 它開始在regexp
的lastIndex
屬性指定的字符位置搜索string
。 當找到匹配項時,它會將lastIndex
設置為匹配后第一個字符的位置。
我認為任何定期使用JavaScript RegExps的人都會認識到這段話。 但是,我在這個方法中發現了一個奇怪的行為。
請考慮以下代碼:
>> rx = /^(.*)$/mg
>> tx = 'foo\n\nbar'
>> rx.exec(tx)
[foo,foo]
>> rx.lastIndex
3
>> rx.exec(tx)
[,]
>> rx.lastIndex
4
>> rx.exec(tx)
[,]
>> rx.lastIndex
4
>> rx.exec(tx)
[,]
>> rx.lastIndex
4
RegExp似乎停留在第二行,並且不會增加lastIndex
屬性。 這似乎與犀牛書相矛盾。 如果我自己設置如下,它繼續並最終返回null按預期,但似乎我不應該。
>> rx.lastIndex = 5
5
>> rx.exec(tx)
[bar,bar]
>> rx.lastIndex
8
>> rx.exec(tx)
null
顯然,只要匹配為空字符串,我就可以增加lastIndex
屬性。 但是,作為好奇的類型,我想知道為什么它不會被exec
方法增加。 為什么不呢?
我在Chrome和Firefox中觀察到了這種行為。 它似乎只有在有相鄰的換行符時才會發生。
Tomalak在下面說,將模式更改為/^(.+)$/gm
將導致表達式不被卡住,但空行被忽略。 這可以改為仍然匹配線? 感謝Tomalak的答案!
使用以下模式並使用組1適用於我能想到的所有字符串。 再次感謝Tomalak 。
/^(.*)((\r\n|\r|\n)|$)/gm
上一個模式返回空行。 但是,如果您不關心空白行, Tomalak會給出以下解決方案,我認為該解決方案更清晰。
/^(.*)[\r\n]*/gm
前兩個解決方案都停留在尾隨換行符上,因此您必須手動剝離它們或遞增lastIndex
。
我在Flagrant Badassery找到了一篇很好的文章,詳細介紹了lastIndex
的跨瀏覽器問題。 除了令人敬畏的博客名稱,這篇文章讓我對這個問題有了更深入的了解,並提供了一個很好的跨瀏覽器解決方案。 解決方案如下:
var rx = /^/gm,
tx = 'A\nB\nC',
m;
while(m = rx.exec(tx)){
if(!m[0].length && rx.lastIndex > m.index){
--rx.lastIndex;
}
foo();
if(!m[0].length){
++rx.lastIndex;
}
}
問題在於點
^(.*)$
與新行字符不匹配,但使用"m"
開關,您可以將"^"
和"$"
錨定為新行字符。 這意味着"\\n"
和"\\n"
”之間的“無”可以與"(.*)"
成功匹配。
由於此匹配的寬度為零,因此lastIndex
屬性無法前進。 嘗試:
^(.+)$
編輯:要匹配空白行,請執行以下操作:
^(.*)\n? // remove all \r characters beforehand
要么
^(.*)(?:\r\n|\n\r|\n|\r)? // all possible CR/LF combinations, but *once* at most
......然后去比賽組1。
lastIndex的問題在於遵循該字母標准的JavaScript實現將其設置為匹配后的下一個字符的偏移量。 對於像你這樣的正則表達式,它允許零長度匹配,因此當找到零長度匹配時,exec()將陷入無限循環。 下一次匹配嘗試將從相同位置開始,其中找到相同的零長度匹配。
傳統上,正則表達式引擎通過在找到零長度匹配時跳過一個字符來處理此問題。 順便提一下,Internet Explorer也是這樣做的。
我過去在博客中詳細介紹了這一點: 注意零長度匹配
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.