replace() and replaceAll(), RegExp allowed (yay?)
The JavaScript String Methods series
- Part 0 - toUpperCase() and toLowerCase()
- Part 1 - split() and join()
- Part 2 - slice(), substring(), substr()
- Part 3 - charAt(), charCodeAt(), fromCharCode(), at()
- Part 4 - concat() and repeat()
- Part 5 - search() and includes()
- Part 6 - indexOf() and lastIndexOf()
- Part 7 - endsWith() and startsWith()
- Part 8 - match() and matchAll()
- You are herePart 9 - replace() and replaceAll()
- Part 10 - trim(), trimEnd() and trimStart()
- Part 11 - padStart() and padEnd()
In this post, skip to:
replace
replace()
is super versatile. It takes two parameters, the pattern you're looking for and the replacement for it. It'll then return a new string with the changes in place.
The pattern can be expressed as a string or as a regular expression. The replacement can be a string or a function.
This opens up a lot of variations, so let's go over each at a time.
replace string by a string
First, let's replace a string by another string.
- This will only affect the first occurrence of the string we are looking for.
- If the first parameter can't be found in the original string, it'll just return the string unchanged.
- Not including a second parameter will return undefined as a replacement
- If your first parameter is an empty string, the replacement will be added to the start of the string
const string = 'This magical bridge of hope and wonder!'
let findString = 'This'
let replacementString = 'That'
string.replace(findString, replacementString)
//output: 'That magical bridge of hope and wonder!'
string.replace('bridge', 'world')
//output: 'This magical world of hope and wonder!'
string.replace('book', 'world')
//output: 'This magical bridge of hope and wonder!'
string.replace('wonder')
//output: 'This magical bridge of hope and undefined!'
string.replace('o', 'ey')
//output: 'This magical bridge eyf hope and wonder!'
string.replace('', 'That')
//output: 'ThatThis magical bridge of hope and wonder!'
Adding modifiers
You can also add a few modifiers into your replacement string to adjust the behavior of the replacement!
- " $& " will make it so you find the pattern, but just add to it rather than fully replace it
- " $` " (that's a backtick) will find the pattern and then replace it with all that comes before the match
- " $' " (that's a single quote) will find the pattern and then replace it with all that comes after the match
const string = 'This magical bridge of hope and wonder!'
string.replace('This', '$&ee')
//output: 'Thisee magical bridge of hope and wonder!'
string.replace('wonder', '$&-eeeeeeeeerrr')
//output: 'This magical bridge of hope and wonder-eeeeeeeeerrr!'
string.replace('wonder', '$`WHAT')
//output: 'This magical bridge of hope and This magical bridge of hope and WHAT!'
string.replace('wonder', '$`')
//output: 'This magical bridge of hope and This magical bridge of hope and !'
string.replace('wonder', "$'")
//output: 'This magical bridge of hope and !!'
string.replace('bridge', "$'")
//output: 'This magical of hope and wonder! of hope and wonder!'
There are also the $n
and the $<GroupName>
modifiers but these work with RegExp only, which brings us to our next step.
With a regular expression and a string
Useful to remember that we can easily pass an i
ignore case flag and/or a global g
flag with our regular expression so replace()
isn't limited to the first match it finds!
const string = "This magical bridge of hope and wonder!"
//note that we don't have a lowercase 'this' in the string
string.replace(/this/, 'A')
//output: 'This magical bridge of hope and wonder!'
//ignore case and then it works!
string.replace(/this/i, 'A')
//output: 'A magical bridge of hope and wonder!'
string.replace(/a/g, 'ay')
//output: 'This maygicayl bridge of hope aynd wonder!'
string.replace(/\This\s\w+/g, 'Oh')
//output: 'Oh bridge of hope and wonder!'
Using regular expressions also opens up more modifiers, in addition to the ones we saw above
$n
can go from$1
to$99
and inserts the capturing groups from our regular expression$<GroupName>
inserts a named capturing group according to the GroupName you assign to said group
// " $' " trying one of the previous modifiers
string.replace(/This\s\w+/g, "$' Oh")
//output: ' bridge of hope and wonder! Oh bridge of hope and wonder!'
// this establishes group 1, (This), and group 2, (a word)
string.replace(/(This)\s(\w+)/g, 'Oh')
//output: 'Oh bridge of hope and wonder!'
string.replace(/(This)\s(\w+)/g, 'Oh, $2! $1')
//output: 'Oh, magical! This bridge of hope and wonder!'
string.replace(/(?<group1>This)\s(?<group2>\w+)/g, 'What, $<group2>?? $<group1>')
//output: 'What, magical?? This bridge of hope and wonder!'
Replacing with a function
You can use a function as the second parameter, and the result of this function will be the replacement!
It takes a few arguments, but you don't have to use all of them. Take into account whether your first replace()
parameter is a string or regular expression, if you have defined groups, if you have named groups, etc.
Here's the map for the function:
function replacer(match, p1, p2, /* …, */ pN, offset, string, groups) {
return replacement;
}
- Match: this is the string you're looking to replace, and corresponds to the modifier
$&
- p1, p2, ..., pN: these are the groups you defined, whether named or not. Correspond to
$1
,$2
, etc - offset: this is the index of the match within the string, pretty useful in case you have identical matches but only wish to replace a specific one
- string: the whole string being examined
- groups: an object with keys referring to group names you've used in your regular expression
Again, you don't have to use all the arguments if you don't want or need them.
Here's an example of how to use a function to convert your match (or parts of it) to uppercase:
const string = "This magical bridge of hope and wonder!"
function stringToUpperCase(example) {
return example.toUpperCase();
}
string.replace('wonder', stringToUpperCase)
//output: 'This magical bridge of hope and WONDER!'
function groupsWithUpperCase(liopleurodon, p1, p2) {
return p1.toUpperCase() + '... um, ' + p1 + ' ' + p2.toUpperCase();
}
string.replace(/(This)\s(\w+)/g, groupsWithUpperCase)
//output: 'THIS... um, This MAGICAL bridge of hope and wonder!'
My naming is... unique. Liopleurodon, really? That's just to show you can name your arguments however you want, but in order to use a p2
group you need something in the position of p1
, and to use p1
you need something in the position of match
.
Even if you don't use match
and only want access to p2
, there's no way the replacer function would know what part of its possible arguments you're trying to change if you didn't include them in order.
If you don't need a p3
, or offset
, etc, then you can just not include them.
replaceAll
replaceAll()
works very similarly to replace()
, with a few key differences:
replaceAll()
will replace all the matches without the need for RegExp!- If you use a regular expression to look for a match, then the global
g
flag is required- in
replace()
the globalg
flag was optional.
- in
- If the pattern you supply as the first parameters is an empty string (
''
), then it'll insert the replacement between every UTF-16 code unit (usually, between every character)- in
replace()
, it would just append the replacement to the start of the string
- in
Let's use the same parameters and see the differences in output between replace()
and replaceAll()
:
const string = 'Here comes a school of poisonous fugu fish!'
//---- String as the first parameter
string.replace('o', 'O')
//output: 'Here cOmes a school of poisonous fugu fish!'
string.replaceAll('o', 'O')
//output: 'Here cOmes a schOOl Of pOisOnOus fugu fish!'
//---- A regular expression without a global flag
string.replace(/!/, '...')
//output: 'Here comes a school of poisonous fugu fish...'
string.replaceAll(/!/, '...')
//output: Uncaught TypeError
//---- A regular expression with a global flag
string.replace(/o/g, 'O')
//output: 'Here cOmes a schOOl Of pOisOnOus fugu fish!'
string.replaceAll(/o/g, 'O')
//output: 'Here cOmes a schOOl Of pOisOnOus fugu fish!'
//---- An empty string as the first parameter
string.replace('', '=')
//output: '=Here comes a school of poisonous fugu fish!'
string.replaceAll('', '=')
//output: '=H=e=r=e= =c=o=m=e=s= =a= =s=c=h=o=o=l= =o=f= =p=o=i=s=o=n=o=u=s= =f=u=g=u= =f=i=s=h=!='
//---- A function as a replacement
function stringToUpperCase(match) {
return match.toUpperCase();
}
string.replace('f', stringToUpperCase)
//output: 'Here comes a school oF poisonous fugu fish!'
string.replaceAll('f', stringToUpperCase)
//output: 'Here comes a school oF poisonous Fugu Fish!'
string.replace(/[aeiou][aeiou]/, stringToUpperCase)
//output: 'Here comes a schOOl of poisonous fugu fish!'
string.replaceAll(/[aeiou][aeiou]/, stringToUpperCase)
//output: Uncaught TypeError
string.replaceAll(/[aeiou][aeiou]/g, stringToUpperCase)
//output: 'Here comes a schOOl of pOIsonOUs fugu fish!'
Phew, the replace()
siblings were quite a handful but they both open up a lot of possibilities!
Practice time
These 7 and 8-kyu CodeWars katas are a fun challenge: