In JavaScript, the String.prototype.replace()
method is used to replace parts of a string with new substrings. It allows you to
perform simple to complex string replacements based on either a static string or a regular expression pattern.
When the first argument is a regular expression, the method will use the regular expression to search for matches within the original string and
then replace those matches with the specified replacement. If the second argument is a string, the method will use it as the static replacement for
the matched substrings found by the regular expression.
Within the replacement string, the function supports special placeholders to insert the matched values of capturing groups from the regular
expression:
- The
$n
syntax allows you to reference capturing groups by their numerical index. The number n
corresponds to the
order in which the capturing group appears in the regular expression, starting from 1 for the first capturing group.
- The
$<Name>
syntax allows you to reference capturing groups by their name. Instead of using numerical indices, you can
assign a name to a capturing group using ?<Name>
within the regular expression.
If the second argument of String.prototype.replace()
references non-existing groups (capturing groups that do not exist in the regular
expression), the behavior of the replacement will depend on the specific references made. It won’t cause an error, but the replacement will not be
based on any captured values, potentially leading to unexpected results in the replaced string:
- If the replacement string contains references like
$1
, $2
, etc., to capturing groups that don’t exist in the regular
expression, those references will be treated as literals. In other words, the $n
will be replaced with the literal text $n
itself.
- If the replacement string contains references like
$<Name>
, they will also be treated as literals, but only if there are no
named captures in the regular expression; otherwise, they will be replaced with the empty string.
This rule checks that all referenced groups exist when replacing a pattern with a replacement string using String.prototype.replace()
or String.prototype.replaceAll()
methods.
const str = 'John Doe';
console.log(str.replace(/(\w+)\s(\w+)/, '$1, $0 $1')); // Noncompliant: index is 1-based, '$0' does not exist, prints 'John, $0 John'
console.log(str.replace(/(?<firstName>\w+)\s(?<lastName>\w+)/, '$<surname>, $<firstName> $<surname>')); // Noncompliant: '$<surname>' does not exist but there are named captures, prints ', John '
Always check your regular expression and replacement string to ensure they properly reference existing capturing groups, most specifically, the
latter references capturing groups existing in the former.
const str = 'John Doe';
console.log(str.replace(/(\w+)\s(\w+)/, '$2, $1 $2'));
console.log(str.replace(/(?<firstName>\w+)\s(?<lastName>\w+)/, '$<lastName>, $<firstName> $<lastName>'));