【问题标题】:RegExp.exec() returns NULL sporadicallyRegExp.exec() 偶尔返回 NULL
【发布时间】:2011-06-11 02:46:23
【问题描述】:

我真的为此发疯了,而且我已经花费了不成比例的时间来试图弄清楚这里发生了什么。所以请帮我一把=)

我需要对 JavaScript 中的字符串进行一些正则表达式匹配。不幸的是,它的行为非常奇怪。这段代码:

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。我不明白为什么。

我发布了一个 Fiddle here,您可以在其中运行和编辑代码。

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

【问题讨论】:

  • 它似乎只在"I have a cat and a dog too." 上失败,似乎
  • exec 如果匹配失败,则返回 null,因此由于某种原因它无法匹配。

标签: javascript regex


【解决方案1】:

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

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);
}

【讨论】:

  • 哇——“正则表达式的内部指针”?你能推荐一个关于那个的资源吗?谢谢!
  • 哇...在过去的 14 年里,我一直在密集地编写 JavaScript,而在过去的 8 年里,RexExps 越来越密集——这让我大吃一惊。如果我更擅长 Perl,我会对此有更好的理解吗?
【解决方案2】:

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

【讨论】:

  • 感谢您的解释!设置myRe.lastIndex = 0; 以供后续使用会很有帮助。
  • 我认为这应该是正确的答案,因为它遵循重用相同正则表达式对象的最佳实践
  • 同意这应该是正确的答案。它重用了相同的正则表达式对象并解释了内部机制。 OP 应该考虑改变。
【解决方案3】:

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

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

我添加这个以防其他人遇到与上述解决方案相同的问题。

【讨论】:

  • 此“错误”已在 ES5 中修复。最初,文字正则表达式只实例化一次。因此,没有必要将它们存储在变量中。以前简洁的while(/a/g.exec(text)) {...} 现在必须写成regex = /a/g; while(regex.exec(text)) {...}。可能这种更改破坏了网络上的许多代码,但更不容易出错。另一方面,当您想在每次执行后重置lastIndex 时,正确的解决方案始终只是删除g 标志。
【解决方案4】:

两件事:

  1. 使用g(全局)标志时提到的reset需要。为了解决这个问题,我建议简单地将0 分配给RegExp 对象的lastIndex 成员。这比销毁和重建具有更好的性能。
  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>");
    }
  }

【讨论】:

  • 这应该是正确的答案。设置 rx.lastIndex = 0 比在循环内重新创建 RegEx 对象要好得多。
  • 当你不想要它时最好不要使用g 标志。创建一个专门更新lastIndex 的正则表达式只是为了在每次执行后重置它是没有意义的。
  • 您可能确实想在一个项目中进行全局搜索,然后在下一个项目中重置并重用正则表达式。我认为 OP 代码只是展示不理解的示例。
猜你喜欢
  • 2014-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-06-12
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 2015-08-27
  • 2015-02-26
相关资源
最近更新 更多