Terminology used in this answer:
- Match indicates the result of running your RegEx pattern against your string like so:
someString.match(regexPattern)
.
- Matched patterns indicate all matched portions of the input string, which all reside inside the match array. These are all instances of your pattern inside the input string.
- Matched groups indicate all groups to catch, defined in the RegEx pattern. (The patterns inside parentheses, like so:
/format_(.*?)/g
, where (.*?)
would be a matched group.) These reside within matched patterns.
Description
To get access to the matched groups, in each of the matched patterns, you need a function or something similar to iterate over the match. There are a number of ways you can do this, as many of the other answers show. Most other answers use a while loop to iterate over all matched patterns, but I think we all know the potential dangers with that approach. It is necessary to match against a new RegExp()
instead of just the pattern itself, which only got mentioned in a comment. This is because the .exec()
method behaves similar to a generator function – it stops every time there is a match, but keeps its .lastIndex
to continue from there on the next .exec()
call.
Code examples
Below is an example of a function searchString
which returns an Array
of all matched patterns, where each match
is an Array
with all the containing matched groups. Instead of using a while loop, I have provided examples using both the Array.prototype.map()
function as well as a more performant way – using a plain for
-loop.
Concise versions (less code, more syntactic sugar)
These are less performant since they basically implement a forEach
-loop instead of the faster for
-loop.
// Concise ES6/ES2015 syntax
const searchString =
(string, pattern) =>
string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
// Or if you will, with ES5 syntax
function searchString(string, pattern) {
return string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
Performant versions (more code, less syntactic sugar)
// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
let result = [];
const matches = string.match(new RegExp(pattern.source, pattern.flags));
for (let i = 0; i < matches.length; i++) {
result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
};
// Same thing, but with ES5 syntax
function searchString(string, pattern) {
var result = [];
var matches = string.match(new RegExp(pattern.source, pattern.flags));
for (var i = 0; i < matches.length; i++) {
result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
I have yet to compare these alternatives to the ones previously mentioned in the other answers, but I doubt this approach is less performant and less fail-safe than the others.
matchAll
is used, the returned value will be an "iterator" (an "iterable iterator" to be more precise), BUT NOT an "array", so e.g.,for(const match of matches)
will work, butmatches[0]
will beundefined
. Also note that the returned iterator is non-restartable. – Bookman