对具有全局选项的模式,对RegExp测试的连续调用失败

时间:2011-07-18 20:38:56

标签: javascript regex

我整天都在努力解决这个问题,我无法弄清楚我是在做错事还是在Chrome的JavaScript引擎中发现了一个错误。看来,使用全局标志对RegExp对象的连续调用会返回相同输入字符串的不一致结果。我正在测试以下功能:

function testRegex(pattern, array) {
    document.writeln('Pattern = ' + pattern + ', Array = ' + array + '<br/>');
    for (var ii = 0; ii < array.length; ii++) {
        document.writeln(ii + ', ');
        document.writeln(array[ii] + ', ');
        document.writeln(pattern.test(array[ii]) + '<br />');
    }
    document.writeln('<br/>');
}

当我用/a/g作为模式和各种字符串数组调用函数时,我得到以下结果,据我所知,其中很多都是错误的:

// EXPECTED: True
// ACTUAL:   True
testRegex(/a/g, ['a']);

// EXPECTED: True,  True
// ACTUAL:   True,  False 
testRegex(/a/g, ['a', 'a']);

// EXPECTED: True, True,  True
// ACTUAL:   True, False, True
testRegex(/a/g, ['a', 'a', 'a']);

// EXPECTED: True, False, True
// ACTUAL:   True, False, True
testRegex(/a/g, ['a', 'b', 'a']);

// EXPECTED: True, True,  True, True
// ACTUAL:   True, False, True, False
testRegex(/a/g, ['a', 'a', 'a', 'a']);

// EXPECTED: True, False, False, True
// ACTUAL:   True, False, False, True   
testRegex(/a/g, ['a', 'b', 'b', 'a']);

当我使用相同的字符串数组调用相同的函数,但传递/a/作为模式时,实际结果都与预期结果匹配。

// EXPECTED: True
// ACTUAL:   True
testRegex(/a/, ['a']);

// EXPECTED: True, True
// ACTUAL:   True, True
testRegex(/a/, ['a', 'a']);

// EXPECTED: True, True, True
// ACTUAL:   True, True, True
testRegex(/a/, ['a', 'a', 'a']);

// EXPECTED: True, False, True
// ACTUAL:   True, False, True
testRegex(/a/, ['a', 'b', 'a']);

// EXPECTED: True, True, True, True
// ACTUAL:   True, True, True, True
testRegex(/a/, ['a', 'a', 'a', 'a']);

// EXPECTED: True, False, False, True
// ACTUAL:   True, False, False, True
testRegex(/a/, ['a', 'b', 'b', 'a']);

我已经创建了上面代码的工作示例:http://jsfiddle.net/FishBasketGordo/gBWsN/

我错过了什么吗?对于给定的字符串数组,结果是否应该相同,无论模式是否为全局?请注意,我主要是在Chrome中工作,但我在Firefox 4和IE 8中观察到类似的错误结果。

2 个答案:

答案 0 :(得分:15)

如果您按如下方式更改测试循环:

for (var ii = 0; ii < array.length; ii++) {
    document.writeln(ii + ', ');
    document.writeln(array[ii] + ', ');
    document.writeln(pattern.test(array[ii]) + '<br />');
    pattern.lastIndex = 0;
}

然后你的代码就可以了。问题是“g”标志导致RegExp对象卡住。由于“g”,在该循环的第一次迭代之后,“lastIndex”值被设置为1。如果你没有将它重新设置为重置搜索,那么它会假定在第二次调用时你要求它继续从偏移量1开始。

在“.replace()”调用的上下文之外的正则表达式上使用“g”标志无论如何都会产生奇怪的语义含义。

答案 1 :(得分:6)

这不是一个错误,而是一个功能。你得到的结果不是“不正确”,只是出乎意料。

10.3.2。 RegExp实例属性

每个RegExp对象都有五个属性。 source属性是一个只读字符串,其中包含正则表达式的文本。 global属性是一个只读布尔值,指定正则表达式是否具有g标志。 ignoreCase属性是一个只读布尔值,指定正则表达式是否具有i标志。 multiline属性是一个只读布尔值,指定正则表达式是否具有m标志。 final属性是lastIndex,一个读写整数。对于带有g标志的模式,此属性将位置存储在字符串中,下一次搜索将在该字符串中开始。它由exec()和test()方法使用,如上一节中所述。

Source