意外的Javascript RegExp行为

时间:2013-03-21 23:11:14

标签: javascript regex google-chrome

我创建一个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限定符是否应该以这种方式使用? (我正在为多个任务重复使用相同的表达式,因此完全具有限定符)

3 个答案:

答案 0 :(得分: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标记是没有意义的。

答案 1 :(得分:6)

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

此处类似的问答:Why is Regex Javascript //g flag affecting state?

答案 2 :(得分:1)

根据MDN

  

exec(或与其结合使用)一样,test多次调用   在同一个全局正则表达式实例上将超越   上一场比赛。

从技术上讲,ECMAScript 5.1规范说

  

15.10.6.3 RegExp.prototype.test(字符串)

     

采取以下步骤:

     
      
  1. 让match为使用 string 作为此RegExp对象评估RegExp.prototype.exec(15.10.6.2)算法的结果   参数。
  2.   
  3. 如果匹配不为null,则返回true;否则返回false
  4.         

    15.10.6.2 RegExp.prototype.exec(字符串)

         

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

         

    搜索字符串ToString( string )是否存在   正则表达式如下:

         
        
    1. R 成为此RegExp对象。
    2.   
    3. [...]
    4.   
    5. [...]
    6.   
    7. lastIndex 成为使用参数" lastIndex"调用 R 的[[Get]]内部方法的结果。
    8.   
    9. i 为ToInteger( lastIndex )的值。
    10.   
    11. global 成为使用参数" global"调用 R 的[[Get]]内部方法的结果。
    12.   
    13. 如果全球false,则让 i = 0.
    14.   
    15. [...]
    16.   
    17. [...]
    18.   
    19. e 成为 r endIndex 值。
    20.   
    21. 如果全球true,   
          
      1. 使用参数" lastIndex", e 和{{1}调用 R 的[[Put]]内部方法}}。
      2.   
    22.   
    23. [...]
    24.   

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

  • 避免使用全局标记true

    这样,在第7步,gi而不是0

  • 每次使用后手动重置lastIndex

      

    lastIndex属性的值指定String位置   哪个开始下一场比赛。

    例如,

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

    searchmatch重置为0,lastIndex忽略它:

      

    15.5.4.10 String.prototype.match(regexp)

         

    [...] [If] global search,使用参数"调用 rx 的[[Put]]内部方法。 true"和0. [...]

         

    15.5.4.12 String.prototype.search(regexp)

         

    [...]从值的开头搜索值 string   正则表达式模式 rx 。 [...] lastIndexlastIndex   执行搜索时,将忽略 regexp 的属性。 [...]

    例如,

    global