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

Consecutive calls to RegExp test fail for pattern with global option

本文关键字:调用 连续 RegExp 测试 失败 模式 于具 全局 选项      更新时间:2023-09-26

我一整天都在纠结这个问题,我不知道我是否做错了什么,或者我是否在Chrome的JavaScript引擎中发现了一个bug。似乎连续调用具有全局标志的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中也观察到类似的错误结果。

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

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"标志会产生奇怪的语义含义。

这不是一个bug,而是一个特性。你得到的结果不是"不正确",只是出乎意料。

10.3.2。RegExp实例属性

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