4

假设我有以下正则表达式代码:

var str = "{$ for ( var i = 0, len = O.length; i < len; i++ ) { $}";

var reg = /\{\$(.*?)\$\}/g;

console.log(reg.test(str));

console.log(reg.test(str));

console.log(reg.test(str));

为什么结果是真假交替?

4

3 回答 3

3

Per docs:

When you want to know whether a pattern is found in a string use the test method (similar to the String.search method); for more information (but slower execution) use the exec method (similar to the String.match method). As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

To illustrate what's happening, we can use exec and see what's happening. In order of passes:

  1. original string (truthy)
    The entire string is matched which is evaluated as true.
  2. null (falsy)
    Consecutive calls continue on, so since the first called returned the entire result, we are left with null.
  3. original string (truthy)
    And the pattern returns back to start and continues on.

For proof, run the following:

var str = '{$ for ( var i = 0, len = O.length; i < len; i++ ) { $}';
var reg = /\{\$(.*?)\$\}/g;
for (var i = 0; i < 3; i++){
    var result = reg.exec(str);
    console.log(result);
    console.log(!!result);
}
于 2013-03-27T03:04:52.147 回答
2

JavaScript RegExps maintain state internally, including fields such as the last index matched. Because of that, you can see some interesting behavior when reusing a regex as in the example you give.

The /g flag would cause it to return true once for each successive match against the given string (of which there only happens to be one in your example), after which it would return false once and then start all over again. Between each call, the aforementioned lastIndex property would be updated accordingly.

Consider the following:

var str = "12";
var regex = /\d/g;

console.log(regex.test(str)); // true
console.log(regex.test(str)); // true
console.log(regex.test(str)); // false

Versus:

console.log(/\d/g.test(str)); // true
console.log(/\d/g.test(str)); // true
console.log(/\d/g.test(str)); // true
console.log(/\d/g.test(str)); // true
// ...and so on, since you're instantiating a new RegExp each time
于 2013-03-27T03:05:01.297 回答
0

Interesting find! I believe it has something to do with your global modifier '/g'. When you remove the global modifier it seems to work as expected. I'm no regex expert; I could only presume that the .test() could be iterating over the $ symbols even though it shouldn't match twice.

于 2013-03-27T03:04:10.983 回答