Reputation: 499
I'm writing a function to recursively replace matches of a regex in a string. The replacement can be a function, as with vanilla .replace
, and this function can access the original string through one of its arguments.
I would like my function to replace only one match on each iteration. With a non-global regex, this will always be the case. However, some of the regexes this function receives will be global. Doing a traditional .replace(regex, replacement)
means it could replace multiple times on each iteration, not only messing up the order in which the matches are processed, but also passing an incorrect index and original string to the replacement function.
As an example:
function recursiveReplace(string, regex, replacement) {
for (var i = 1e8; i > 0 && regex.test(string); i--)
string = string.replace(regex, replacement);
return string;
}
console.log(
recursiveReplace("abcdef", /../g, function (match, index, original) {
console.log(original);
return match[0];
})
);
This outputs
abcdef
abcdef
abcdef
ace
ae
a
when the desired output is
abcdef
acdef
adef
aef
af
a
How can I get the function to process only one match on each iteration, whether the regex has the g
flag or not? Note that I'm using the function in such a way that the second argument will always be a regex (I have no control over this, nor over whether or not said regex has the g
flag).
Upvotes: 7
Views: 1169
Reputation: 499
It would seem that the best way to do this would be to just manually remove the g
flag from the regex. Here's the most cross-platform way I could find to do this, using regex.toString()
to get the string representation of the regex:
function recursiveReplace(string, regex, replacement) {
regex = eval(regex.toString().replace(/[a-z]*$/, function (s) {
return s.replace('g', '');
}));
for (var i = 1e8; i > 0 && regex.test(string); i--)
string = string.replace(regex, replacement);
return string;
}
With the ES6 features RegExp(regex)
and RegExp#flags
this gets much easier:
function recursiveReplace(string, regex, replacement) {
regex = RegExp(regex, regex.flags.replace('g', ''));
for (var i = 1e8; i > 0 && regex.test(string); i--)
string = string.replace(regex, replacement);
return string;
}
Upvotes: 2