Explain Codes LogoExplain Codes Logo

Replace multiple strings with multiple other strings

javascript
functions
regex
performance
Nikita BarsukovbyNikita Barsukov·Aug 28, 2024
TLDR

To do the string-replace dance with javascript, you can use an object (aka: a "map") for your "replace with what" pairs, and a regular expression (regex) to catch them all.

// The strings const map = { 'foo': 'bar', 'hello': 'world' }; // Gotcha! const str = 'foo and hello'; // Oh you sneaky regex... const regex = new RegExp(Object.keys(map).join('|'), 'g'); // Presto jargonisto! const result = str.replace(regex, match => map[match]); console.log(result); // Out: "bar and world", foo now loves to bar, hello is so worldly now.

In this code, we're casting a regex pokeball to catch all keys from our map. Then, replace() craftily uses the caught match to return our corresponding string replacement.

Dance with dynamic replacements

What happens if we have a flashmob of words that keep changing and want to join our replace party? Fear not. Let's choreograph a reusable function to keep the dancefloor open:

// Be a DJ, mix the track to your liking. function replaceMultiple(str, map) { const regex = new RegExp(Object.keys(map).join('|'), 'g'); return str.replace(regex, match => map[match]); } // What's cookin', good lookin'? const text = 'The quick brown fox jumps over the lazy dog'; // Spice it up! const replacements = { 'quick': 'slow', 'brown': 'red', 'lazy': 'active' }; // And serve... const newText = replaceMultiple(text, replacements); console.log(newText); // Out: "The slow red fox jumps over the active dog", that's a plot twist right there!

Don't lose your words

The devil's in the detail and we don't want to replace parts of words like a clumsy DIYer. That's why we use word boundaries \b in our regex to ensure precision:

// Precision... to replace or not to replace! function replaceWholeWords(str, map) { // Mind the boundary! const regex = new RegExp(`\\b(${Object.keys(map).join('|')})\\b`, 'g'); return str.replace(regex, match => map[match]); }

Our regex is now like a well-trained dog, fetching only whole words that match keys in our map.

Safe replacement

In the real world, we don't always find what we're looking for. So we need our function to handle those "oopsie-daisy" situations when the replacement isn't needed:

// Safe and sound replacements. function safeReplace(str, map) { const regex = new RegExp(`\\b(${Object.keys(map).join('|')})\\b`, 'g'); return str.replace(regex, match => map[match] || match); }

With || match, we ensure if a match isn't in our map, the original word sticks around like the loyal friend it is.

Go the extra mile with polyfill

Sometimes, we need to turn back the clock, and for those situations include a polyfill. This way, we're friendly with the older browsers:

if (!String.prototype.replaceAll) { // When technology gets old, get a polyfill! String.prototype.replaceAll = function(str, newStr) { return this.replace(new RegExp(str, 'g'), newStr); }; }

This polyfill brings replaceAll back to the future!

The placeholder trick

Sometimes, string replacement feels like solving a Rubik's cube, with overlapping replacements causing chaos. The solution? Use placeholders:

function sequentialReplace(str, order, map) { // Use your mafia contacts, get some unique placeholders not found in original strings ;) const placeholders = order.map((_, i) => `{{REPLACE${i}}}`); // Swap old strings with new shiny placeholders order.forEach((item, i) => { str = str.replaceAll(item, placeholders[i]); }); // Time for the magic trick. Replace placeholders with new strings. placeholders.forEach((ph, i) => { str = str.replaceAll(ph, map[order[i]]); }); return str; }

This placeholder strategy might seem like a magic trick, but it's simple: First, replace old strings with placeholders, then swap the placeholders with the new strings. Abracadabra!

Using modern syntax

Our modern JavaScript syntax can make our code enlighten:

  1. Arrow functions for short and sweet callbacks:

    str.replace(regex, match => map[match]);
  2. Use template literals to make regex more readable:

    new RegExp(`\\b(${Object.keys(map).join('|')})\\b`, 'g');
  3. Leverage destructuring and spread operator to keep everything neat and tidy:

    const [firstWord, ...restOfWords] = 'The quick brown fox'.split(' '); const newSentence = [firstWord.toUpperCase(), ...restOfWords].join(' ');

Wrapping it up

Your grandma might not understand what 'performance optimization' means but she definitely knows the value of readability. So let's keep that in mind:

  • Consider performance when handling large pieces or numerous replacements.
  • Resort to concise and efficient regular expressions, to avoid unleashing the dark forces within your code.