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

Fis*_*rdo 10 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/>');
}
Run Code Online (Sandbox Code Playgroud)

当我使用/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']);
Run Code Online (Sandbox Code Playgroud)

当我使用相同的字符串数组调用相同的函数,但/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']);
Run Code Online (Sandbox Code Playgroud)

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

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

Poi*_*nty 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;
}
Run Code Online (Sandbox Code Playgroud)

然后你的代码将工作.问题是"g"标志导致RegExp对象卡住.由于"g",在该循环的第一次迭代之后,"lastIndex"值被设置为1.如果你没有将它重新设置为重置搜索,那么它假定在第二次调用时你要求它继续偏移1.

在".replace()"调用的上下文之外的正则表达式上使用"g"标志无论如何都具有奇怪的语义含义.


Hyp*_*eus 6

它不是一个bug,而是一个功能.你得到的结果不是"不正确",只是出乎意料.

10.3.2.RegExp实例属性

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

资源