What is the difference between RegExp’s exec() function and String’s match() function?

JavascriptRegex

Javascript Problem Overview


If I run this:

/([^\/]+)+/g.exec('/a/b/c/d');

I get this:

["a", "a"]

But if I run this:

'/a/b/c/d'.match(/([^\/]+)+/g);

Then I get the expected result of this:

["a", "b", "c", "d"]

What's the difference?

Javascript Solutions


Solution 1 - Javascript

exec with a global regular expression is meant to be used in a loop, as it will still retrieve all matched subexpressions. So:

var re = /[^\/]+/g;
var match;

while (match = re.exec('/a/b/c/d')) {
    // match is now the next match, in array form.
}

// No more matches.

String.match does this for you and discards the captured groups.

Solution 2 - Javascript

One picture is better, you know...

re_once = /([a-z])([A-Z])/
re_glob = /([a-z])([A-Z])/g

st = "aAbBcC"

console.log("match once="+ st.match(re_once)+ "  match glob="+ st.match(re_glob))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))

See the difference?

> Note: To highlight, notice that captured groups(eg: a, A) are returned after the matched pattern (eg: aA), it's not just the matched pattern.

Solution 3 - Javascript

/regex/.exec() returns only the first match found, while "string".match() returns all of them if you use the g flag in the regex.

See here: exec, match.

Solution 4 - Javascript

If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.

Match works great for when just matching(not capturing). You run it once and it gives an array of all the matches. (though if the regex is not global, then match will show the match followed by captures)

Exec is what you use when you are capturing, and each time it is executed it gives the match, followed by the captures. (match will behave in a manner of giving the full match followed by captures, only when the regex is not global).

Another use with Exec, is getting the index or position, of a match. When you have a variable for your regex, you can use .lastIndex and get the position of the matching. A regex object has .lastIndex, and the regex object is what you do .exec on. Dot match is done on a string and you won't be able to then do regex object dot lastIndex

A string, has the match function, which is passed a regex. And a regex, has the exec function, and is passed a string

exec you run multiple times. match you run once

It's good to use match when not capturing and when capturing you can use exec which is more powerful as it is good for getting captures, but if you did use match when capturing, see that it shows captures when the regex is not global, but doesn't show captures when the regex is global.

> "azb".match(/a(z)b/);
[ "azb", "z" ]

> "azb".match(/a(z)b/g);
[ "azb" ]
>

Another thing is that if you use exec, note that's called on the regex, then if you used a variable for the regex, you have more power

You don't get the matches when you don't use the variable for the regex, so use the variable for the regex, when using exec

> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
>
> /[a-c]/g.exec("abc")
[ "a" ]
> /[a-c]/g.exec("abc")
[ "a" ]
>

> var r=/[a-c]/g
> r.exec("abc")
[ "a" ]
> r.exec("abc")
[ "b" ]
> r.exec("abc")
[ "c" ]
> r.exec("abc")
null
>

And with exec, you can get the "index" of the match

> var r=/T/g
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
2
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
6
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
9
> r.exec("qTqqqTqqTq");
null
> r.lastIndex
0
>

So if you want indexes or capturing, then use exec (bear in mind that as you can see, with the "index", the "index" it gives is really an nth occurrence, it's counting from 1. So you could derive the proper index by subtracting 1. And as you can see it gives 0 - lastIndex of 0 - for not found).

And if you want to stretch match, you can use it when you are capturing, but not when the regex is global, and when you do it for that, then the contents of the array aren't all the matches, but are the full match followed by the captures.

Solution 5 - Javascript

The .match() function str.match(regexp) will do the following:

  • if there is a match it will return:
  • if the g flag is used in the regexp: it will return all the substrings (ignoring capture groups)
  • if the g flag is not used in the regexp: it will return the same as regexp.exec(str)
  • if there is no match it will return:
  • null

Examples of .match() using the g flag:

var str = "qqqABApppabacccaba";
var e1, e2, e3, e4, e5;
e1 = str.match(/nop/g); //null
e2 = str.match(/no(p)/g); //null
e3 = str.match(/aba/g); //["aba", "aba"]
e4 = str.match(/aba/gi); //["ABA", "aba", "aba"]
e5 = str.match(/(ab)a/g); //["aba", "aba"] ignoring capture groups as it is using the g flag

And .match() without the g flag is equivalent to .exec():

e1=JSON.stringify(str.match(/nop/))===JSON.stringify(/nop/.exec(str)); //true
//e2 ... e4 //true
e5=JSON.stringify(str.match(/(ab)a/))===JSON.stringify(/(ab)a/.exec(str)); //true

The .exec() function regexp.exec(str) will do the following:

  • if there is a match it will return:
  • if the g flag is used in the regexp: it will return (for each time it is called): [N_MatchedStr, N_Captured1, N_Captured2, ...] of the next N match. Important: it will not advance into the next match if the regexp object is not stored in a variable (it needs to be the same object)
  • if the g flag is not used in the regexp: it will return the same as if it had a g flag and was called for the first time and only once.
  • if there is no match it will return:
  • null

Example of .exec() (stored regexp + using the g flag = it changes with each call):

var str = "qqqABApppabacccaba";
var myexec, rgxp = /(ab)a/gi;

myexec = rgxp.exec(str);
console.log(myexec); //["ABA", "AB"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //null

//But in this case you should use a loop:
var mtch, myRe = /(ab)a/gi;
while(mtch = myRe.exec(str)){ //infinite looping with direct regexps: /(ab)a/gi.exec()
	console.log("elm: "+mtch[0]+" all: "+mtch+" indx: "+myRe.lastIndex);
	//1st iteration = elm: "ABA" all: ["ABA", "AB"] indx: 6
	//2nd iteration = elm: "aba" all: ["aba", "ab"] indx: 12
	//3rd iteration = elm: "aba" all: ["aba", "ab"] indx: 18
}

Examples of .exec() when it is not changing with each call:

var str = "qqqABApppabacccaba", myexec, myexec2;

//doesn't go into the next one because no g flag
var rgxp = /(a)(ba)/;
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
//... ["aba", "a", "ba"]

//doesn't go into the next one because direct regexp
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
//... ["ABA", "AB"]

Solution 6 - Javascript

Sometimes regex.exec() will take much more time then string.match().

It is worth to mention that if the outcome of string.match() and regex.exec() are the same (ex: when not using \g flag), regex.exec() will take somewhere between x2 to x30 then string.match():

Therefore in such cases, using the approach of "new RegExp().exec()" should be used only when you need a global regex (i.e. to execute more than once).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJustin WarkentinView Question on Stackoverflow
Solution 1 - JavascriptRy-View Answer on Stackoverflow
Solution 2 - JavascriptgeorgView Answer on Stackoverflow
Solution 3 - JavascriptAlex CiminianView Answer on Stackoverflow
Solution 4 - JavascriptbarlopView Answer on Stackoverflow
Solution 5 - Javascriptajax333221View Answer on Stackoverflow
Solution 6 - JavascriptdoronyView Answer on Stackoverflow