一些背景
来自 Javascript: The Definitive Guide :
When
regexp
is a global regular expression, however,exec()
behaves in a slightly more complex way. It begins searchingstring
at the character position specified by thelastIndex
preperty ofregexp
. When it finds a match, it setslastIndex
to the position of the first character after the match.
我认为任何经常使用 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
属性。这似乎与The Rhino Book矛盾.如果我自己按如下方式设置它,它会继续并最终按预期返回 null,但似乎我不必这样做。
>> rx.lastIndex = 5
5
>> rx.exec(tx)
[bar,bar]
>> rx.lastIndex
8
>> rx.exec(tx)
null
结论
显然,只要匹配项为空字符串,我就可以递增 lastIndex
属性。但是,作为好奇的类型,我想知道为什么 exec
方法不增加它。为什么不是呢?
注意事项
我在 Chrome 和 Firefox 中观察到了这种行为。它似乎只有在有相邻的换行符时才会发生。
[编辑]
Tomalak下面说把pattern改成/^(.+)$/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"
之间的"nothing"可以和"(.*)"
匹配成功。
由于此匹配项的宽度为零,因此 lastIndex
属性无法前进。尝试:
^(.+)$
编辑:要匹配空白行,请执行以下操作:
^(.*)\n? // remove all \r characters beforehand
或
^(.*)(?:\r\n|\n\r|\n|\r)? // all possible CR/LF combinations, but *once* at most
...然后只去匹配组 1。
关于Javascript - 多行正则表达式 : lastIndex stuck on newlines?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/381214/