RegExp.exec()偶尔返回NULL


83

我为此感到非常疯狂,并且我已经花费了不成比例的时间来试图弄清这里正在发生什么。所以请帮我=)

我需要对JavaScript中的字符串进行RegExp匹配。不幸的是,它的行为非常奇怪。这段代码:

var rx = /(cat|dog)/gi;
var w = new Array("I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.");

for (var i in w) {
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    }else{
        document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
}

按原样返回前两个元素的“ cat”和“ dog”,但随后一些exec()调用开始返回null。我不明白为什么。

我在这里发布了一个小提琴,您可以其中运行和编辑代码。

到目前为止,我已经在Chrome和Firefox中进行了尝试。

干杯!

/克里斯托弗


它只会在a上失败"I have a cat and a dog too.",看来
SilentGhost

如果设计使匹配失败,则exec返回null,因此由于某种原因匹配失败。
马丁·耶斯珀森

Answers:


78

哦,在这里。因为要定义全局正则表达式,所以它首先匹配cat,然后在循环的第二遍匹配dog。因此,基本上,您只需要重置您的正则表达式(它是内部指针)即可。cf. 这个:

var w = new Array("I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.", "I have a cat and a dog too.");

for (var i in w) {
    var rx = /(cat|dog)/gi;
    var m = null;
    m = rx.exec(w[i]);
    if(m){
        document.writeln("<p>" + i + "<br/>INPUT: " + w[i] + "<br/>MATCHES: " + w[i].length + "</p>");
    }else{
        document.writeln("<p><b>" + i + "<br/>'" + w[i] + "' FAILED.</b><br/>" + w[i].length + "</p>");
    }
    document.writeln(m);
}

到了那里,我太慢了:)
Martin Jespersen

啊,甜蜜!我要花一点时间才能弄清楚那个。谢谢!
cpak 2011年

这节省了我很多时间。非常感谢!
Thomas Johansen

这个问题使我怀疑生活。
GZ Xue

我觉得我应该把薪水还给我
cgatian

72

regex对象具有一个lastIndex在运行时会更新的属性exec。因此,当您在例如“我也有猫和狗。”上执行正则表达式时,lastIndex设置为12。下一次exec在同一个正则表达式对象上运行时,它将从索引12开始查找。因此,您必须重置lastIndex属性每次运行之间。


ah,这个网站对我来说太快了。SilentGhost +1 :-)
Frode

8
感谢您的解释!通过设置myRe.lastIndex = 0;供以后使用,它会很有帮助。
2013年

1
哇,非常感谢lastIndex的提示,这真的让我发疯了!
dave0688

1
我认为这应该是正确的答案,因为它遵循重用同一个正则表达式对象的最佳做法
smurtagh,

同意这应该是正确的答案。它重用了同一个正则表达式对象,并解释了内部机制。OP应该考虑进行更改。
肖恩·科利

31

两件事情:

  1. 当使用(全局)标志时,提到需要重置g。为了解决这个问题,我建议您简单地分配0lastIndexRegExp对象的成员。这比销毁并重新创建具有更好的性能。
  2. 使用in关键字行走Array对象时要小心,因为使用某些库可能导致意外结果。有时,您应该检查一些类似的东西isNaN(i),或者,如果您知道它没有孔,请使用经典的for循环。

代码可以是:

var rx = /(cat|dog)/gi;
w = ["I have a cat and a dog too.", "There once was a dog and a cat.", "I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat.","I have a cat and a dog too.", "There once was a dog and a cat."];

for (var i in w)
 if(!isNaN(i))        // Optional, check it is an element if Array could have some odd members.
  {
   var m = null;
   m = rx.exec(w[i]); // Run
   rx.lastIndex = 0;  // Reset
   if(m)
    {
     document.writeln("<pre>" + i + "\nINPUT: " + w[i] + "\nMATCHES: " + m.slice(1) + "</pre>");
    } else {
     document.writeln("<pre>" + i + "\n'" + w[i] + "' FAILED.</pre>");
    }
  }

1
这应该是正确的答案。设置rx.lastIndex = 0比在循环内重新创建RegEx对象好得多。
Minoru

4

我仅使用/ g时遇到了类似的问题,在FireFox 3.6.8中,这里提出的解决方案对我不起作用。我的脚本正在与

var myRegex = new RegExp("my string", "g");

如果有人遇到与上述解决方案相同的问题,则添加此内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.