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.