为什么Javascript';s regex.exec()是否总是返回相同的值?

为什么Javascript';s regex.exec()是否总是返回相同的值?,javascript,regex,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 exec是否有状态,取决于上次返回的内容?或者这只是一个bug?我不能让它一直发生。例如,如果上面的“str”是“abc”,则不会发生这种情况。JavaScriptRe

在Chrome或Firebug控制台中:

reg = /ab/g
str = "abc"
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null

exec是否有状态,取决于上次返回的内容?或者这只是一个bug?我不能让它一直发生。例如,如果上面的“str”是“abc”,则不会发生这种情况。

JavaScript
RegExp
对象是有状态的

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

当没有找到更多匹配项时,索引将自动重置为
0


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

reg.lastIndex = 0;

这是一个非常有用的特性。如果需要,可以在字符串中的任意点开始计算,或者如果在循环中,可以在所需的匹配次数后停止计算


这里演示了在循环中使用正则表达式的典型方法。它利用了这样一个事实,即当不再有匹配项时,
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]);
演示:


如果您不喜欢分配的位置,可以对循环进行返工,例如

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);
演示:来自:

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

由于您使用的是
g
标志,
exec
从最后一个匹配的字符串继续执行,直到结束(返回
null
),然后重新开始


就我个人而言,我更喜欢反过来使用
str.match(reg)

多个匹配项 如果正则表达式需要
g
标志(全局匹配),则需要使用
lastIndex
属性重置索引(上次匹配的位置)

reg.lastIndex=0

这是因为
exec()
将。此行为也存在于
test()
)中:

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

单根火柴
当只有一个可能的匹配项时,您可以通过省略
g
标志来重写regex,作为。

您还可以使用
reg.exec(“”)
重置它,因为它只在传递相同的字符串时保留状态。在
时包含
循环示例可能是一件好事,因为这证明了这个特殊功能的有用性。@Esailija@skint这并不完全正确。如果使用相同的正则表达式来匹配不同的字符串,则
lastIndex
将保持设置为它在第一个字符串中的位置。我今天遇到了这个问题……哦,你是说Esailija的“只有传递相同字符串时才保留状态”评论吗?是的,那不对。他的技术重置了它,因为它无法在空字符串中找到匹配项。也许在某些情况下它不会重置?无论如何,我不会使用这种技巧。如果有人读过这篇文章,这里有一把小提琴来进一步解释我的困境(上面@squint的回答解释了这一点):