Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Javascript's regex.exec() not always return the same value? [duplicate]

In the Chrome or Firebug console:

reg = /ab/g
str = "abc"
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null
reg.exec(str)
   ==> ["ab"]
reg.exec(str)
   ==> null

Is exec somehow stateful and depends on what it returned the previous time? Or is this just a bug? I can't get it to happen all the time. For example, if 'str' above were "abc abc" it doesn't happen.

like image 563
Sam Fen Avatar asked Oct 01 '22 03:10

Sam Fen


People also ask

What does regex exec return?

JavaScript RegExp exec() The exec() method tests for a match in a string. If it finds a match, it returns a result array, otherwise it returns null.

How to reset JavaScript regex?

A JavaScript RegExp object is stateful. When the regex is global, if you call a method on the same regex object, it will start from the index past the end of the last match. When no more matches are found, the index is reset to 0 automatically. To reset it manually, set the lastIndex property.

What is exec function in JavaScript?

exec() The exec() method executes a search for a match in a specified string. Returns a result array, or null . JavaScript RegExp objects are stateful when they have the global or sticky flags set (e.g. /foo/g or /foo/y ).


2 Answers

From MDN docs:

If your regular expression uses the "g" flag, you can use the exec method multiple times to find successive matches in the same string. When you do so, the search starts at the substring of str specified by the regular expression's lastIndex property (test will also advance the lastIndex property).

Since you are using the g flag, exec continues from the last matched string until it gets to the end (returns null), then starts over.


Personally, I prefer to go the other way around with str.match(reg)

like image 31
Niet the Dark Absol Avatar answered Oct 21 '22 20:10

Niet the Dark Absol


A JavaScript RegExp object is stateful.

When the regex is global, if you call a method on the same regex object, it will start from the index past the end of the last match.

When no more matches are found, the index is reset to 0 automatically.


To reset it manually, set the lastIndex property.

reg.lastIndex = 0;

This can be a very useful feature. You can start the evaluation at any point in the string if desired, or if in a loop, you can stop it after a desired number of matches.


Here's a demonstration of a typical approach to using the regex in a loop. It takes advantage of the fact that exec returns null when there are no more matches by performing the assignment as the loop condition.

var re = /foo_(\d+)/g,
    str = "text foo_123 more text foo_456 foo_789 end text",
    match,
    results = [];

while (match = re.exec(str))
    results.push(+match[1]);

DEMO: http://jsfiddle.net/pPW8Y/


If you don't like the placement of the assignment, the loop can be reworked, like this for example...

var re = /foo_(\d+)/g,
    str = "text foo_123 more text foo_456 foo_789 end text",
    match,
    results = [];

do {
    match = re.exec(str);
    if (match)
        results.push(+match[1]);
} while (match);

DEMO: http://jsfiddle.net/pPW8Y/1/

like image 271
3 revs, 2 users 98%user1106925 Avatar answered Oct 21 '22 21:10

3 revs, 2 users 98%user1106925