我整天都在努力解决这个问题,我无法弄清楚我是在做错事还是在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中观察到类似的错误结果。
答案 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()方法使用,如上一节中所述。