8
votes

I wrote a Javascript RegExp test to detect date string format, I added an redundant "g" flag by mistake and found something interesting.

var s = "2009/03/10";
var regex=/^\d{4}[/]\d{2}[/]\d{2}$/g;
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));

I got a 'true' followed by a 'false', then another 'true', then another 'false'.

If I use a loop to execute it, I found something more interesting, I got four "true" in IE and Safari, and true,false,true,false in FF, Chrome.

for (var i=0; i<4; i++)
{
  var s = "2009/03/10";
  var regex=/^\d{4}[/]\d{2}[/]\d{2}$/g;
  alert(regex.test(s));
}

Does anybody has idea to explain why the Javascript regex behaves like that and what cause browsers return different results? ( related to variable declaration and life scope? )

2

2 Answers

21
votes

When you use a global flag on a JS RegExp the "test" and "exec" methods each halt at the first match but keep a pointer to where they stopped searching in the string. That pointer can be inspected on the lastIndex property. When you call "test" or "exec" again it begins searching for a match starting at the lastIndex.

So, when you test a RegExp on a string that matches the entire string the lastIndex is set to the end of the string. The next time you test it starts at the end of the string, returns false, and sets lastIndex back to zero.

The MDC has a decent explanation of this behavior.

0
votes

To avoid this weird behavior don't use the global (g) flag.

This code should output: 'True','True','True','True'

var s = "2009/03/10";
var regex=/^\d{4}[/]\d{2}[/]\d{2}$/i;
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));
alert(regex.test(s));

The global (g) flat set the property RegExp.lastIndex. So each test() will start where the last one stopped.

For more info see documentation about RegExp.lastIndex