Exec()偶尔返回 NULL

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

我需要在 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 中尝试过了。

25236 次浏览

Oh, here it is. Because you're defining your regex global, it matches first cat, and on the second pass of the loop dog. So, basically you just need to reset your regex (it's internal pointer) as well. Cf. this:

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

The regex object has a property lastIndex which is updated when you run exec. So when you exec the regex on e.g. "I have a cat and a dog too.", lastIndex is set to 12. The next time you run exec on the same regex object, it starts looking from index 12. So you have to reset the lastIndex property between each run.

I had a similar problem using /g only, and the proposed solution here did not work for me in FireFox 3.6.8. I got my script working with

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

I'm adding this in case someone else has the same problem I did with the above solution.

Two things:

  1. The mentioned need of reset when using the g (global) flag. To solve this I recommed simply assign 0 to the lastIndex member of the RegExp object. This have better performance than destroy-and-recreate.
  2. Be careful when use ABC0 keyword in order to walk an Array object, because can lead to unexpected results with some libs. Sometimes you should check with somethign like isNaN(i), or if you know it don't have holes, use the classic for loop.

The code can be:

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