Reemplace varias cadenas con varias otras cadenas

Resuelto Anderson Green asked hace 11 años • 28 respuestas

Estoy intentando reemplazar varias palabras en una cadena con varias otras palabras. La cadena es "Tengo un gato, un perro y una cabra".

Sin embargo, esto no produce "Tengo un perro, una cabra y un gato", sino que produce "Tengo un gato, un gato y un gato". ¿Es posible reemplazar varias cadenas con otras cadenas al mismo tiempo en JavaScript, de modo que se produzca el resultado correcto?

var str = "I have a cat, a dog, and a goat.";
str = str.replace(/cat/gi, "dog");
str = str.replace(/dog/gi, "goat");
str = str.replace(/goat/gi, "cat");

//this produces "I have a cat, a cat, and a cat"
//but I wanted to produce the string "I have a dog, a goat, and a cat".
Anderson Green avatar Mar 25 '13 04:03 Anderson Green
Aceptado

Solución específica

Puede utilizar una función para reemplazar cada uno.

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];
});

ejemplo de jsfiddle

Generalizándolo

Si desea mantener dinámicamente la expresión regular y simplemente agregar intercambios futuros al mapa, puede hacer esto

new RegExp(Object.keys(mapObj).join("|"),"gi"); 

para generar la expresión regular. Entonces se vería así

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];
});

Y para agregar o cambiar más reemplazos, simplemente puede editar el mapa. 

jugar con expresiones regulares dinámicas

Hacerlo reutilizable

Si desea que este sea un patrón general, puede extraerlo de una función como esta

function replaceAll(str,mapObj){
    var re = new RegExp(Object.keys(mapObj).join("|"),"gi");

    return str.replace(re, function(matched){
        return mapObj[matched.toLowerCase()];
    });
}

Entonces podría simplemente pasar la cadena y un mapa de los reemplazos que desea a la función y devolvería la cadena transformada.

jugar con la función

Para garantizar que Object.keys funcione en navegadores más antiguos, agregue un polyfill, por ejemplo, de MDN o Es5 .

Ben McCormick avatar Mar 24 '2013 21:03 Ben McCormick

Como respuesta a:

buscando una respuesta actualizada

Si está utilizando "palabras" como en el ejemplo actual, puede ampliar la respuesta de Ben McCormick utilizando un grupo sin captura y agregar límites de palabras \ba la izquierda y a la derecha para evitar coincidencias parciales.

\b(?:cathy|cat|catch)\b
  • \bUn límite de palabra para evitar una coincidencia parcial
  • (?:Grupo de no captura
    • cathy|cat|catchcoincide con una de las alternativas
  • )Cerrar grupo sin captura
  • \bUn límite de palabra para evitar una coincidencia parcial

Ejemplo de la pregunta original:

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);
Expandir fragmento

Ejemplo del ejemplo en los comentarios que no parece funcionar bien:

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);
Expandir fragmento

The fourth bird avatar May 03 '2021 19:05 The fourth bird

Utilice elementos numerados para evitar reemplazarlos nuevamente. p.ej

let str = "I have a %1, a %2, and a %3";
let pets = ["dog","cat", "goat"];

entonces

str.replace(/%(\d+)/g, (_, n) => pets[+n-1])

Cómo funciona: %\d+ encuentra los números que vienen después de %. Los corchetes capturan el número.

Este número (como una cadena) es el segundo parámetro, n, de la función lambda.

+n-1 convierte la cadena en un número y luego se resta 1 para indexar la matriz de mascotas.

Luego, el número % se reemplaza con la cadena en el índice de la matriz.

/g hace que la función lambda se llame repetidamente con cada número que luego se reemplaza con una cadena de la matriz.

En JavaScript moderno: -

replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])
Quentin 2 avatar May 18 '2018 12:05 Quentin 2

Es posible que esto no satisfaga su necesidad exacta en este caso, pero he descubierto que es una forma útil de reemplazar múltiples parámetros en cadenas, como solución general. Reemplazará todas las instancias de los parámetros, sin importar cuántas veces se haga referencia a ellos:

String.prototype.fmt = function (hash) {
        var string = this, key; for (key in hash) string = string.replace(new RegExp('\\{' + key + '\\}', 'gm'), hash[key]); return string
}

Lo invocarías de la siguiente manera:

var person = '{title} {first} {last}'.fmt({ title: 'Agent', first: 'Jack', last: 'Bauer' });
// person = 'Agent Jack Bauer'
Iian avatar Mar 24 '2013 23:03 Iian

usando Array.prototype.reduce() :

Respuesta ACTUALIZADA (mucho mejor) (usando objeto): esta función reemplazará todas las apariciones y no distingue entre mayúsculas y minúsculas

/**
 * Replaces all occurrences of words in a sentence with new words.
 * @function
 * @param {string} sentence - The sentence to modify.
 * @param {Object} wordsToReplace - An object containing words to be replaced as the keys and their replacements as the values.
 * @returns {string} - The modified sentence.
 */
function replaceAll(sentence, wordsToReplace) {
  return Object.keys(wordsToReplace).reduce(
    (f, s, i) =>
      `${f}`.replace(new RegExp(s, 'ig'), wordsToReplace[s]),
      sentence
  )
}

const americanEnglish = 'I popped the trunk of the car in a hurry and in a hurry I popped the trunk of the car'
const wordsToReplace = {
  'popped': 'opened',
  'trunk': 'boot',
  'car': 'vehicle',
  'hurry': 'rush'
}

const britishEnglish = replaceAll(americanEnglish, wordsToReplace) 
console.log(britishEnglish)
// I opened the boot of the vehicle in a rush and in a rush I opened the boot of the vehicle

Respuesta ORIGINAL (usando una variedad de objetos):

    const arrayOfObjects = [
      { plants: 'men' },
      { smart:'dumb' },
      { peace: 'war' }
    ]
    const sentence = 'plants are smart'
    
    arrayOfObjects.reduce(
      (f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence
    )

    // as a reusable function
    const replaceManyStr = (obj, sentence) => obj.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

    const result = replaceManyStr(arrayOfObjects , sentence1)

Ejemplo

// /////////////    1. replacing using reduce and objects

// arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

// replaces the key in object with its value if found in the sentence
// doesn't break if words aren't found

// Example

const arrayOfObjects = [
  { plants: 'men' },
  { smart:'dumb' },
  { peace: 'war' }
]
const sentence1 = 'plants are smart'
const result1 = arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence1)

console.log(result1)

// result1: 
// men are dumb


// Extra: string insertion python style with an array of words and indexes

// usage

// arrayOfWords.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence)

// where arrayOfWords has words you want to insert in sentence

// Example

// replaces as many words in the sentence as are defined in the arrayOfWords
// use python type {0}, {1} etc notation

// five to replace
const sentence2 = '{0} is {1} and {2} are {3} every {5}'

// but four in array? doesn't break
const words2 = ['man','dumb','plants','smart']

// what happens ?
const result2 = words2.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence2)

console.log(result2)

// result2: 
// man is dumb and plants are smart every {5}

// replaces as many words as are defined in the array
// three to replace
const sentence3 = '{0} is {1} and {2}'

// but five in array
const words3 = ['man','dumb','plant','smart']

// what happens ? doesn't break
const result3 = words3.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence3)

console.log(result3)

// result3: 
// man is dumb and plants
Expandir fragmento

Emmanuel N K avatar Jun 18 '2019 03:06 Emmanuel N K