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).
sub() method will replace all pattern occurrences in the target string. By setting the count=1 inside a re. sub() we can replace only the first occurrence of a pattern in the target string with another string. Set the count value to the number of replacements you want to perform.
For example, the replacement pattern $1 indicates that the matched substring is to be replaced by the first captured group.
The Regex. Replace(String, String, MatchEvaluator, RegexOptions) method is useful for replacing a regular expression match if any of the following conditions is true: If the replacement string cannot readily be specified by a regular expression replacement pattern.
The replace() method returns a new string with one, some, or all matches of a pattern replaced by a replacement . The pattern can be a string or a RegExp , and the replacement can be a string or a function called for each match. If pattern is a string, only the first occurrence will be replaced.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With