4

Say I have the following regular expression code:

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

Why is the result an alternation of True and False?

Michael Currie
  • 13,721
  • 9
  • 42
  • 58

2 Answers2

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);
}
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
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
dfreeman
  • 2,834
  • 2
  • 20
  • 24