The String#replace()
function replaces instances of a substring with another substring, and returns the modified string. This function seems simple at first, but String#replace()
can do a whole lot more than just replace 'foo' with 'bar'. In this article, I'll explain some more sophisticated ways to use String#replace()
, and highlight some common pitfalls to avoid.
The Basics of Replacing a String
JavaScript strings are immutable,
so the String#replace()
function returns the modified string. It does not modify
the existing string.
const str1 = 'foo bar';
const str2 = str1.replace('foo', 'bar');
str1; // 'foo bar'
str2; // 'bar bar'
Generally, the first argument to replace()
is called the pattern, and the 2nd
argument is called the replacement. In the above example, 'foo' is the pattern
and 'bar' is the replacement.
By default, replace()
only replaces the first instance of the pattern. In
the below example, JavaScript only replaces the first instance of 'foo' with 'bar'.
'foo foo'.replace('foo', 'bar'); // 'bar foo'
Unfortunately, in my experience it's rare you only want to replace the first instance of a substring. To make JavaScript replace all instances of a substring rather than just one, you need to use a regular expression.
RegExps and the global
Flag
To replace all instances of 'foo' in a string, you need to use a
regular expression with the /g
flag.
// Note the 'g' after `/foo/`
'foo foo'.replace(/foo/g, 'bar'); // 'bar bar'
// Without 'g', `replace()` will only replace the first 'foo'
'foo foo'.replace(/foo/, 'bar'); // 'bar foo'
Using the /str/
syntax can be inconvenient if the string you want to replace
has slashes or special characters. In that case, you can use
JavaScript's RegExp
constructor.
// Pass 'g' as the 2nd argument to set the global flag
const re = new RegExp('/home/user', 'g');
'/home/user/path/to/file.txt'.replace(re, '~'); // '~/path/to/file.txt'
re.global; // true
If you want to make sanitize user input to make it safe to use with RegExps and
.replace()
, you should use the escape-string-regexp
package.
const escapeString = require('escape-string-regexp');
// Without escaping the string, `new RegExp('.*')` gives you a RegExp
// that matches any string, rather than just instances of '.*'.
const re = new RegExp(escapeString('.*'), 'g');
'.* .*'.replace(re, 'foo'); // foo foo
Replacement Patterns
There are several special character sequences that you can use in the 2nd argument to replace()
.
For example, suppose you want to wrap all numbers in a string in parentheses.
JavaScript replaces $&
in the replacement string with the matched string,
so you can wrap all numbers in parentheses as shown below. Note that JavaScript
does not treat the replacement string as a regular expression, so you don't
need to escape the parentheses.
const str = 'Like example 1, example 2 also shows this pattern';
// 'Like example (1), example (2) also shows this pattern'
str.replace(/\d+/g, '($&)');
A slightly more tricky task is prefixing all numbers in a string with a dollar
sign '$'. Using $$&
as your replacement will not give you the right result.
You need to use $$$&
with 3 $
characters.
// Year over year revenue grew from $4M to $5M
'Year over year revenue grew from 4M to 5M'.replace(/\d+/g, '$$$&');
If you want to add a single $
sign immediately before a replacement pattern,
you need to escape it by using $$
.
You only need to escape $
if you're using it immediately before $
, &
, `
, '
. You also need to escape $
if it immediately precedes a digit and you're using capture groups.
For example, you do not need to escape $
if the next character in the replacement is a space:
// Year over year revenue grew from $ 4M to $ 5M
'Year over year revenue grew from 4M to 5M'.replace(/\d+/g, '$ $&');
Passing a Function as the Replacement
You can get extra fancy and pass a function as the replacement. JavaScript will call your replacement function for every instance of the pattern, and replace with the return value of your replacement function.
JavaScript calls your replacement function with 3 parameters unless you use a RegExp capture group. The 3 arguments are:
name
: The substring matched by the patternoffset
: The index of the start ofname
in the whole stringstring
: The string you calledreplace()
on.
Here's an example:
const values = ['foo', 'bar', 'baz'];
// The below replaces '1 2 3' with 'foo bar baz'
'1 2 3'.replace(/\d+/g, function(name, offset, string) {
// This function is called 3 times
name; // '1', '2', '3'
offset; // 0, 2, 4
string; // Always '1 2 3'
return values[Number(name) - 1]; // return 'foo', 'bar', 'baz'
});
Moving On
Replacing substrings in JavaScript has some common pitfalls, most notably only
replacing only the first instance of the substring by default. But JavaScript
makes up for it with replacement patterns and replacement functions, which allow
for some powerful string manipulation patterns. Tricky tasks like prefixing
all numbers in a string with dollar signs become elegant one-liners. Try out
replacement patterns or replacement functions next time you're tempted to
chain together .split().map().join()
.