Replace multiple strings with multiple other strings
Specific Solution
You can use a function to replace each one.
var str = "I have a cat, a dog, and a goat.";var mapObj = { cat:"dog", dog:"goat", goat:"cat"};str = str.replace(/cat|dog|goat/gi, function(matched){ return mapObj[matched];});
Generalizing it
If you want to dynamically maintain the regex and just add future exchanges to the map, you can do this
new RegExp(Object.keys(mapObj).join("|"),"gi");
to generate the regex. So then it would look like this
var mapObj = {cat:"dog",dog:"goat",goat:"cat"};var re = new RegExp(Object.keys(mapObj).join("|"),"gi");str = str.replace(re, function(matched){ return mapObj[matched];});
And to add or change any more replacements you could just edit the map.
Making it Reusable
If you want this to be a general pattern you could pull this out to a function like this
function replaceAll(str,mapObj){ var re = new RegExp(Object.keys(mapObj).join("|"),"gi"); return str.replace(re, function(matched){ return mapObj[matched.toLowerCase()]; });}
So then you could just pass the str and a map of the replacements you want to the function and it would return the transformed string.
To ensure Object.keys works in older browsers, add a polyfill eg from MDN or Es5.
As an answer to:
looking for an up-to-date answer
If you are using "words" as in your current example, you might extend the answer of Ben McCormick using a non capture group and add word boundaries \b
at the left and at the right to prevent partial matches.
\b(?:cathy|cat|catch)\b
\b
A word boundary to prevent a partial match(?:
Non capture groupcathy|cat|catch
match one of the alternatives
)
Close non capture group\b
A word boundary to prevent a partial match
Example for the original question:
let str = "I have a cat, a dog, and a goat.";const mapObj = { cat: "dog", dog: "goat", goat: "cat"};str = str.replace(/\b(?:cat|dog|goat)\b/gi, matched => mapObj[matched]);console.log(str);
Example for the example in the comments that not seems to be working well:
let str = "I have a cat, a catch, and a cathy.";const mapObj = { cathy: "cat", cat: "catch", catch: "cathy"};str = str.replace(/\b(?:cathy|cat|catch)\b/gi, matched => mapObj[matched]);console.log(str);
Use numbered items to prevent replacing again.eg
let str = "I have a %1, a %2, and a %3";let pets = ["dog","cat", "goat"];
then
str.replace(/%(\d+)/g, (_, n) => pets[+n-1])
How it works:-%\d+ finds the numbers which come after a %. The brackets capture the number.
This number (as a string) is the 2nd parameter, n, to the lambda function.
The +n-1 converts the string to the number then 1 is subtracted to index the pets array.
The %number is then replaced with the string at the array index.
The /g causes the lambda function to be called repeatedly with each number which is then replaced with a string from the array.
In modern JavaScript:-
replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])