为什么Javascript的regex.exec()并不总是返回相同的值?

Sam*_*Fen 102 javascript regex

在Chrome或Firebug控制台中:

reg = /ab/g
str = "abc"
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null
Run Code Online (Sandbox Code Playgroud)

exec在某种程度上是有状态的,取决于它之前返回的内容吗?或者这只是一个错误?我无法让它一直发生.例如,如果上面的'str'是"abc abc",则不会发生.

小智 189

JavaScript RegExp对象是有状态的.

当正则表达式是全局的时,如果在同一个正则表达式对象上调用方法,它将从最后一次匹配结束后的索引开始.

如果找不到更多匹配项,索引将0自动重置为.


要手动重置,请设置lastIndex属性.

reg.lastIndex = 0;
Run Code Online (Sandbox Code Playgroud)

这可能是一个非常有用的功能.如果需要,您可以在字符串中的任何位置开始评估,或者如果在循环中,您可以在所需数量的匹配后停止评估.


这是一个在循环中使用正则表达式的典型方法的演示.它利用了通过执行赋值作为循环条件而在没有更多匹配时exec返回的事实null.

var re = /foo_(\d+)/g,
    str = "text foo_123 more text foo_456 foo_789 end text",
    match,
    results = [];

while (match = re.exec(str))
    results.push(+match[1]);
Run Code Online (Sandbox Code Playgroud)

演示: http : //jsfiddle.net/pPW8Y/


如果您不喜欢分配的位置,可以重新设置循环,例如......

var re = /foo_(\d+)/g,
    str = "text foo_123 more text foo_456 foo_789 end text",
    match,
    results = [];

do {
    match = re.exec(str);
    if (match)
        results.push(+match[1]);
} while (match);
Run Code Online (Sandbox Code Playgroud)

演示: http : //jsfiddle.net/pPW8Y/1/

  • 您也可以使用`reg.exec("")`重置它,因为它只保留传递相同字符串的状态 (5认同)
  • @Esailija @squint并不完全正确.如果你使用相同的正则表达式匹配不同的字符串,那么`lastIndex`仍然设置为它在第一个字符串中的位置.我今天遇到了这个问题. (3认同)
  • ...哦,您是在谈论Esailija的*“仅在传递相同字符串时才保留状态” *评论吗?是的,那是不对的。他的技术将其重置,因为它无法在空字符串中找到匹配项。也许在某些情况下无法重置?无论如何,我不会使用那种技术。 (2认同)

Nie*_*sol 17

来自MDN文档:

如果正则表达式使用"g"标志,则可以多次使用exec方法在同一字符串中查找连续匹配.执行此操作时,搜索从正则表达式的lastIndex属性指定的str的子字符串开始(test也将使lastIndex属性前进).

由于您正在使用该g标志,exec从最后一个匹配的字符串继续,直到它到达结尾(返回null),然后重新开始.


就个人而言,我更喜欢用另一种方式 str.match(reg)


Édo*_*pez 9

多个匹配

如果正则表达式需要g标志(全局匹配),则需要使用lastIndex属性重置索引(最后一个匹配的位置).

reg.lastIndex = 0;

这是因为每次出现exec()都会停止,因此您可以在剩余部分再次运行.此行为也存在test()):

如果正则表达式使用"g"标志,则可以多次使用exec方法在同一字符串中查找连续匹配.执行此操作时,搜索从正则表达式的lastIndex属性指定的str的子字符串开始(test也将提前执行​​lastIndex属性)

单场比赛

当只有一个可能的匹配时,您可以通过省略该g标志来简单地重写您的正则表达式,因为索引将自动重置为0.