views:

582

answers:

1

Why do javascript sub-matches stop working when the g modifier is set?

var text = 'test test test test';

var result = text.match(/t(e)(s)t/);
// result: ["test", "e", "s"]

the above works fine... [1] is e and [2] is s... perfect

var result = text.match(/t(e)(s)t/g);
// ["test", "test", "test", "test"]

the above it screwed... it ignores my sub-matches

var result = text.match(/test/g);
for (i in result) {
    console.log(result[i].match(/t(e)(s)t/));
}
/*
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
*/

is the above the only valid solution?

thanks to htw the proper way to do this would be the following:

var pattern = new RegExp(/t(e)(s)t/g);
while (match = pattern.exec(text))
{
    console.log(match);
}
+9  A: 

Using String's match() function won't return captured groups if the global modifier is set, as you found out.

In this case, you would want to use a RegExp object and call its exec() function. String's match() is almost identical to RegExp's exec() function…except in cases like these. If the global modifier is set, the normal match() function won't return captured groups, while RegExp's exec() function will. (Noted here, among other places.)

Another catch to remember is that exec() doesn't return the matches in one big array—it keeps returning matches until it runs out, in which case it returns null.

So, for example, you could do something like this:

var pattern = /t(e)(s)t/g;  // You could also use "new RegExp(/t(e)(s)t/g);"
var match;    

while (match = pattern.exec(text))
{
    // Do something with the match (["test", "e", "s"]) here...
}

You can find information on how to use RegExp objects on W3Schools (specifically, here's the documentation for the exec() function).

htw
using exec doesn't seem to listen to the g modifier, but it supports sub-matches/groups. So the result would be the first match (it basically ignores the g modifier)
Chad Scira
Added a clarification about that—you have to call exec() repeatedly to get the multiple matches.
htw
Not the most elegant solution.i was expecting an output somewhat like this:[ ["test", "e", "s"], ["test", "e", "s"], ["test", "e", "s"], ["test", "e", "s"]]
Chad Scira
htw: good clarification. One little nit-pick: you don't really need to pass the regex literal through new RegExp().
Shog9
@Shog9: Thanks, I forgot about that. Edited to reflect that.
htw
ok very nice, its interesting that you have to do it this way. Thanks :)
Chad Scira