Reemplazar cadenas múltiples con otras cadenas múltiples

213

Estoy tratando de 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 varias cadenas al mismo tiempo en JavaScript, para 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
fuente
Quiero reemplazar varias palabras en una cadena con varias otras palabras, sin reemplazar las palabras que ya han sido reemplazadas.
Anderson Green
Tengo una consulta diferente, ¿qué pasa si no sé si el usuario va a ingresar gato o perro o cabra (esto viene al azar) pero cada vez que esta palabra llegue, necesito reemplazar con digamos 'animal'. cómo obtener este escenario
Prasanna Sasne

Respuestas:

445

Solución especifica

Puede usar una función para reemplazar cada una.

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 solo agregar futuros intercambios al mapa, puede hacerlo

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, puede editar el mapa. 

violín con regex dinámico

Haciéndolo reutilizable

Si desea que este sea un patrón general, puede llevarlo a 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 pasar la cadena y un mapa de los reemplazos que desea a la función y devolvería la cadena transformada.

violín con función

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

Ben McCormick
fuente
44
No estoy seguro si podría usar esta función para reemplazar todos los tipos de cadenas, ya que los caracteres permitidos en las cadenas de JavaScript no son los mismos que los permitidos en los identificadores de JavaScript (como las teclas que se usan aquí) .
Anderson Green
2
puede usar una cadena arbitraria como propiedad de javascript. No debería importar Simplemente no puede usar la .notación con todas esas propiedades. La notación de corchetes funciona con cualquier cadena.
Ben McCormick
2
De hecho funciona muy bien. Estoy usando con éxito esta solución (la 'específica') para cambiar las anotaciones de números en inglés a las europeas (24,973.56 a 24.973,56), usando map={'.': ',', ',': '.'}y regex /\.|,/g.
Sygmoral
55
Me encanta esta solución, pero tuve que reemplazarla return mapObj[matched.toLowerCase()];solo return mapObj[matched];porque uso mayúsculas y minúsculas mapObj.
Michal Moravcik
2
Es posible que desee escapar de las claves para la expresión regular: Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'). Inspirado por esta respuesta
robsch
9

Es posible que esto no satisfaga su necesidad exacta en este caso, pero he encontrado que es una forma útil de reemplazar múltiples parámetros en cadenas, como una 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
fuente
8

Use elementos numerados para evitar reemplazarlos nuevamente. p.ej

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

luego

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

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

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

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

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

El / 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
fuente
Interesante. ¿Puedes explicar la lógica en la función de reemplazo?
Eric Hepperle - CodeSlayer2010
5

Esto funcionó para mí:

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

function replaceAll(str, map){
    for(key in map){
        str = str.replaceAll(key, map[key]);
    }
    return str;
}

//testing...
var str = "bat, ball, cat";
var map = {
    'bat' : 'foo',
    'ball' : 'boo',
    'cat' : 'bar'
};
var new = replaceAll(str, map);
//result: "foo, boo, bar"
Joao Paulo
fuente
No funciona si la cadena contiene caracteres regex.
Roemer
Acerca de "no extender ...": extendí mi Cadena para comparar dos cadenas de igualdad, sin distinción entre mayúsculas y minúsculas. String no proporciona esta funcionalidad, pero podría ser algún día, lo que podría causar que mis aplicaciones se rompan. ¿Hay alguna forma de "subclasificar" o "extender" una cadena para incluir dicha función de forma segura, o debería simplemente definir una nueva función de dos argumentos como parte de mi biblioteca de aplicaciones?
David Spector
4

utilizando Array.prototype.reduce () :

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

Emmanuel NK
fuente
La mejor respuesta. Pero, ¿hay alguna razón para usar en ${f}lugar de f para el valor acumulado?
David Spector
1
Si desea reemplazar TODAS las cadenas dadas, no solo la primera, agregue el indicador g: "const result1 = arrayOfObjects.reduce ((f, s) => ${f}.replace (new RegExp (Object.keys (s) [ 0], 'g'), s [Object.keys (s) [0]]), oración1) "
David Spector
2

En caso de que alguien se pregunte por qué la solución del póster original no funciona:

var str = "I have a cat, a dog, and a goat.";

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

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

str = str.replace(/goat/gi, "cat");
// now str = "I have a cat, a cat, and a cat."
Jack
fuente
ja ja ... bien analizado ... pulgar arriba
Deepa MG
1

función regular del usuario para definir el patrón a reemplazar y luego usar la función de reemplazo para trabajar en la cadena de entrada,

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');
KARTHIKEYAN.A
fuente
Si no sabe omitir, pero no diga que es la respuesta incorrecta. Mi caso "{" a ": 1," b ": 2}" como ese es el que usé para reemplazar la forma anterior. Si ayuda a otros si quieren a otros, la respuesta no es solo para usted. @Carr
KARTHIKEYAN.A
Una vez más, que acaba de proporcionar una respuesta sin sentido, lo que se hace es el autor de la pregunta ya se puede hacer en la pregunta, esta respuesta va a engañar a la gente para que puedan pensar nuevo y utilizar el RegExpobjeto podría resolver el problema
Carr
En este caso, todavía tiene el mismo problema que la pregunta del autor cuando lo hacevar i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
Carr
1

Con mi paquete replace-once , puede hacer lo siguiente:

const replaceOnce = require('replace-once')

var str = 'I have a cat, a dog, and a goat.'
var find = ['cat', 'dog', 'goat']
var replace = ['dog', 'goat', 'cat']
replaceOnce(str, find, replace, 'gi')
//=> 'I have a dog, a goat, and a cat.'
Kodie Grantham
fuente
Este paquete es increíble :) Funciona exactamente como esperaba
Vishnu Prassad
1
    var str = "I have a cat, a dog, and a goat.";

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

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

    str = str.replace(/cat/i, "dog");
    // now str = "I have a dog, a goat, and a cat."
Anand Kumar Singh
fuente
3
El OP preguntó "¿Es posible reemplazar varias cadenas con varias otras cadenas al mismo tiempo ". Estos son tres pasos separados.
LittleBobbyTables - Au Revoir
1

Puede buscar y reemplazar cadenas con delimitadores.

var obj = {
  'firstname': 'John',
  'lastname': 'Doe'
}

var text = "My firstname is {firstname} and my lastname is {lastname}"

console.log(mutliStringReplace(obj,text))

function mutliStringReplace(object, string) {
      var val = string
      var entries = Object.entries(object);
      entries.forEach((para)=> {
          var find = '{' + para[0] + '}'
          var regExp = new RegExp(find,'g')
       val = val.replace(regExp, para[1])
    })
  return val;
}

Naresh Kumar
fuente
0
String.prototype.replaceSome = function() {
    var replaceWith = Array.prototype.pop.apply(arguments),
        i = 0,
        r = this,
        l = arguments.length;
    for (;i<l;i++) {
        r = r.replace(arguments[i],replaceWith);
    }
    return r;
}

/ * replaceSome método para cadenas que toma tantos argumentos como queramos y los reemplaza todos con el último argumento que especificamos 2013 CopyRights guardado para: Max Ahmed este es un ejemplo:

var string = "[hello i want to 'replace x' with eat]";
var replaced = string.replaceSome("]","[","'replace x' with","");
document.write(string + "<br>" + replaced); // returns hello i want to eat (without brackets)

* /

jsFiddle: http://jsfiddle.net/CPj89/

nazih ahmed
fuente
0
<!DOCTYPE html>
<html>
<body>



<p id="demo">Mr Blue 
has a           blue house and a blue car.</p>

<button onclick="myFunction()">Try it</button>

<script>
function myFunction() {
    var str = document.getElementById("demo").innerHTML;
    var res = str.replace(/\n| |car/gi, function myFunction(x){

if(x=='\n'){return x='<br>';}
if(x==' '){return x='&nbsp';}
if(x=='car'){return x='BMW'}
else{return x;}//must need



});

    document.getElementById("demo").innerHTML = res;
}
</script>

</body>
</html>
Jalaluddin Rumi
fuente
0

Escribí este paquete npm stringinject https://www.npmjs.com/package/stringinject que le permite hacer lo siguiente

var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);

que reemplazará {0} y {1} con los elementos de la matriz y devolverá la siguiente cadena

"this is a test string for stringInject"

o podría reemplazar marcadores de posición con claves de objeto y valores de esta manera:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

"My username is tjcafferkey on Github" 
tjcafferkey
fuente
0

Puede usar https://www.npmjs.com/package/union-replacer para este propósito. Básicamente es una string.replace(regexp, ...)contraparte, lo que permite que sucedan múltiples reemplazos en una sola pasada, al tiempo que conserva la potencia total de string.replace(...).

Divulgación: soy el autor. La biblioteca se desarrolló para admitir reemplazos configurables por el usuario más complejos y aborda todas las cosas problemáticas como grupos de captura, referencias inversas y reemplazos de funciones de devolución de llamada.

Sin embargo, las soluciones anteriores son lo suficientemente buenas para el reemplazo exacto de cadenas.

Martin Čížek
fuente
-1

Me expandí un poco en @BenMcCormicks. Trabajó para cadenas regulares, pero no si hubiera escapado de personajes o comodines. Esto es lo que hice.

str = "[curl] 6: blah blah 234433 blah blah";
mapObj = {'\\[curl] *': '', '\\d: *': ''};


function replaceAll (str, mapObj) {

    var arr = Object.keys(mapObj),
        re;

    $.each(arr, function (key, value) {
        re = new RegExp(value, "g");
        str = str.replace(re, function (matched) {
            return mapObj[value];
        });
    });

    return str;

}
replaceAll(str, mapObj)

devuelve "bla bla 234433 bla bla"

De esta forma, coincidirá con la clave en mapObj y no con la palabra coincidente '

Drew Landgrave
fuente
// sin valor: replaceAll ("Tengo un gato, un perro y una cabra", {cat: "perro", perro: "cabra", cabra: "gato"}) // produce: "Tengo un gato , un gato y un gato ".
devon
-3

Solución con Jquery (primero incluya este archivo): reemplace varias cadenas con varias otras cadenas:

var replacetext = {
    "abc": "123",
    "def": "456"
    "ghi": "789"
};

$.each(replacetext, function(txtorig, txtnew) {
    $(".eng-to-urd").each(function() {
        $(this).text($(this).text().replace(txtorig, txtnew));
    });
});
Súper modelo
fuente
¿Esta solución requiere JQuery?
Anderson Green
etiqueta javascript agregada en cuestión, y jquery es una biblioteca de javascript.
Súper modelo el
2
@Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm, esa lógica está desactivada, debería ser al revés, y también solo un aviso: desde la información de la etiqueta de JavaScript: " A menos que también se incluya otra etiqueta para un marco / biblioteca, se espera una respuesta de JavaScript pura " .
Traxo
@ Anderson Green, sí, se necesita jquery para el script anterior.
Súper modelo
@ Traxo, en la mayoría de las aplicaciones web estamos usando framework (bootstrap / google material). Jquery incluye en todos los marcos modernos. Entonces, jquery es un elemento necesario para las aplicaciones web.
Super Model