Happy toast

JavaScript String Replace Magic

  1. javascript
  2. regex

Replacing strings in JavaScript is a fairly common task, but there are some nuances that might surprise the uninitiated, not to mention some really powerful features just below the surface. Read on to see.


The Simple Case

The most obvious way to do string replacement is by passing 2 strings to replace(), the string to find and the string to replace it with.

var str = 'Needs more salt!';
str.replace('salt', 'pepper');
// "Needs more pepper!"

replace() does not change the value of str, rather it returns a new string with the applied replacements (this example doesn’t do anything with the returned string, but you’d probably want to).

It’s worth mentioning that this approach is case sensitive. Searching for “Salt” in the above example would come up empty.

Replacing All Occurrences

There is one major caveat: this approach only replaces the first occurrence.

var str = 'badger badger badger badger';
str.replace('badger', 'mushroom');
// "mushroom badger badger badger"

This is often not what you want. To replace all occurrences, you’ll want to use the regex flavored version of replace().

var str = 'badger badger badger badger';
str.replace(/badger/g, 'mushroom');
// "mushroom mushroom mushroom mushroom"

The g flag is crucial. That’s what makes it a global search, finding all occurrences. But what if you want to specify a string to replace via a variable, instead of hardcoding “badger”? It’s a little more typing, but not hard to do with a RegExp object.

var str = 'badger badger badger badger';
var substr = 'badger';
str.replace(new RegExp(substr, 'g'), 'mushroom');
// "mushroom mushroom mushroom mushroom"

We’re dealing with regex now, so don’t forget to escape characters that have special meaning or you’ll get weird syntax errors. Just stick a \ in front of them.

var str = '1 + 1 + 1 = 3';
str.replace(/\+/g, 'plus');
// "1 plus 1 plus 1 = 3"

Doing More with Regex

Opening the door to regex lets us do more interesting things. For example, replacing multiple words at once. While we’re at it, let’s solve that case-sensitivity issue from earlier.

var str = 'Waiting on Zoe, Elena, and Cal.';
str.replace(/zoe|elena|cal/gi, 'someone');
// "Waiting on someone, someone, and someone."

The | element lets us create an “or” list of terms. And you probably spotted the i flag, which makes the replacements case insensitive.

Here’s something fancier. The following looks for 3 digit numbers and replaces them with the same number, but with dashes between the digits.

var str = 'Your winning cash 3 number is 419.';
str.replace(/(\d)(\d)(\d)/g, '$1-$2-$3');
// "Your winning cash 3 number is 4-1-9."

\d is a special regex element that matches any single digit, so we use 3 of those to find 3 digit numbers. Each one is wrapped in parenthesis (), which lets us reference them in the replacement string. $1 is replaced with whatever was matched in the first set of parenthesis, $2 with what’s in the second, and so on.

We’ve barely scratched the surface of what can be done with regex. You can do some amazing things, but that’s an entire post (if not an entire book) of its own.

Replacement Functions

Sometimes you may want to do something completely custom when replacing text, something that not even regex can handle. Our next example replaces fractions with their decimal equivalents.

var str = 'Add 1/4 cup of sugar and 1/2 cup of blueberries.'
str.replace(/(\d+)\/(\d+)/g, function(match, submatch1, submatch2) {
var num1 = parseInt(submatch1);
var num2 = parseInt(submatch2);
return (num1 / num2).toString();
// "Add 0.25 cup of sugar and 0.5 cup of blueberries."

\d+ means “one or more digits in a row”. We do this twice, both times wrapped in parenthesis, so we can catch the numerator and denominator. In the middle is \/, which is simply an escaped slash /. Put it all together and we’ve got a fraction finder.

This time, instead of a string for the second parameter of replace(), we’re providing a function. This function is called every time a match is found and its return value is what replaces the match. The function takes a couple parameters, though we’re only using 3 in this example. The parameters are, in order:

  • match - The matching string that was found.
  • submatch1, submatch2, … - Each set of parenthesis used will add a submatch parameter. It’s the same concept as the $1, $2, etc. stuff from earlier.
  • offset - How far into the string this match is, in number of characters.
  • string - The entire original string that we called replace() on.

The code within the function does the actual fraction/decimal conversion. It takes the first submatch (numerator) and second submatch (denominator), converts them both to integers, divides them to get the decimal value, then returns that as a string.

We’re just dividing numbers here, but you have the freedom to write whatever custom string replacement code you want. Go nuts.

Thank you!