9

我创建了一个 RegExp 对象(在 JavaScript 中)来测试数字的存在:

var test = new RegExp( '[0-9]', 'g' );

我这样用

console.log( test.test( '0' ) ); // true
console.log( test.test( '1' ) ); // false - why?

这个输出更令人困惑:

console.log( test.test( '1' ) ); // true
console.log( test.test( '0' ) ); // false - why?
console.log( test.test( '1' ) ); // true
console.log( test.test( '2' ) ); // false - why?
console.log( test.test( '2' ) ); // true - correct, but why is this one true?

如果我删除g限定符,它会按预期运行。

这是我认为的错误,还是规范的某些特殊部分?g限定词应该以这种方式使用吗?(我对多个任务重复使用相同的表达式,因此完全有限定符)

4

3 回答 3

7

每个文档:https ://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test#Description

test在同一个全局正则表达式实例上多次调用将超过上一次匹配。

您可以确认此行为:

var test = new RegExp( '[0-9]', 'g' );
test.test('01'); //true
test.test('01'); //true
test.test('01'); //false

g如果您只想针对各种字符串确认单个匹配项,那么使用该标志是没有意义的。

于 2013-03-21T23:19:33.850 回答
6

删除'g'标志。当您使用'g' 标志时,它会更新lastIndex正则表达式的属性(准备对同一字符串进行连续搜索),然后从该索引值开始下一次搜索(从而在下一次搜索时为您提供错误读数)。

类似的问题和答案在这里:为什么 Regex Javascript //g 标志影响状态?

于 2013-03-21T23:17:17.253 回答
1

根据MDN

exec(或与其结合)一样,test在同一个全局正则表达式实例上多次调用将超过前一个匹配项。

从技术上讲,ECMAScript 5.1 规范说

15.10.6.3正则表达式.prototype.test(字符串)

采取以下步骤:

  1. 让 match 是使用字符串作为参数在此 RegExp 对象上评估RegExp.prototype.exec(15.10.6.2) 算法的结果。
  2. 如果匹配不为空,则返回true;否则返回false

15.10.6.2正则表达式.prototype.exec(字符串)

对正则表达式执行字符串的正则表达式匹配,并返回一个包含匹配结果的 Array 对象,或者null如果字符串不匹配。

在 String ToString( string ) 中搜索正则表达式模式的出现,如下所示:

  1. R成为这个 RegExp 对象。
  2. [...]
  3. [...]
  4. lastIndex为使用参数 " " 调用R的 [[Get]] 内部方法的结果lastIndex
  5. i为 ToInteger( lastIndex ) 的值。
  6. global为使用参数 " " 调用R的 [[Get]] 内部方法的结果global
  7. 如果全局false,则令i = 0。
  8. [...]
  9. [...]
  10. erendIndex值。
  11. 如果全局true,
    1. 使用参数“ ”、e和调用R的 [[Put]] 内部方法。lastIndextrue
  12. [...]

因此,为避免这种行为,您可以

  • 避免使用全局标志g

    这样,在第 7 步,i0代替lastIndex.

  • lastIndex每次使用后手动重置

    lastIndex属性的值指定开始下一个匹配的字符串位置。

    例如,

    var test = /[0-9]/g;
    test.test('0');      // true
    test.lastIndex;      // 1
    test.lastIndex = 0;
    test.test('1');      // true
    
  • 使用matchsearch字符串方法

    match重置lastIndex为 0,并search忽略它:

    15.5.4.10 String.prototype.match(正则表达式)

    [...] [If] global is ,使用参数“ ”和 0 调用rxtrue的 [[Put]] 内部方法。[...]lastIndex

    15.5.4.12 String.prototype.search(正则表达式)

    [...] 从值字符串的开头搜索正则表达式模式rx的出现。[...] regexplastIndex的andglobal 属性在执行搜索时被忽略。[...]

    例如,

    var test = /[0-9]/g;
    test.test('0');        // true
    test.lastIndex;        // 1
    '0'.search(test) > -1; // true
    test.lastIndex;        // 1 (unaltered)
    !!'0'.match(test);     // true
    test.lastIndex;        // 0
    
于 2014-10-30T18:49:19.527 回答