Substitua várias strings por várias outras strings

213

Estou tentando substituir várias palavras em uma string por várias outras palavras. A sequência é "Eu tenho um gato, um cachorro e uma cabra".

No entanto, isso não produz "Eu tenho um cachorro, uma cabra e um gato", mas produz "Eu tenho um gato, um gato e um gato". É possível substituir várias seqüências de caracteres por várias outras ao mesmo tempo em JavaScript, para que o resultado correto seja produzido?

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
fonte
Desejo substituir várias palavras em uma seqüência de caracteres por várias outras palavras, sem substituir palavras que já foram substituídas.
Anderson Green
Eu tenho uma consulta diferente, e se eu não souber que o usuário vai entrar em um gato, cachorro ou cabra (isso acontece aleatoriamente), mas sempre que essa palavra aparecer, eu preciso substituir por, digamos, 'animal'. como obter este cenário
Prasanna Sasne

Respostas:

445

Solução específica

Você pode usar uma função para substituir cada uma.

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

exemplo jsfiddle

Generalizando

Se você deseja manter dinamicamente a regex e apenas adicionar trocas futuras ao mapa, você pode fazer isso

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

para gerar o regex. Então, ficaria assim

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

E para adicionar ou alterar mais substituições, você pode apenas editar o mapa. 

violino com regex dinâmico

Tornando reutilizável

Se você deseja que este seja um padrão geral, você pode extrair isso para uma função 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()];
    });
}

Então, você pode simplesmente passar a string e um mapa das substituições que deseja para a função e ela retornará a string transformada.

mexer com função

Para garantir que Object.keys funcione em navegadores mais antigos, adicione um polyfill, por exemplo, do MDN ou Es5 .

Ben McCormick
fonte
4
Não tenho certeza se eu poderia usar essa função para substituir todos os tipos de cadeias, pois os caracteres permitidos nas cadeias JavaScript não são iguais aos caracteres permitidos nos identificadores JavaScript (como as chaves usadas aqui) .
Anderson Green
2
você pode usar uma sequência arbitrária como uma propriedade javascript. Não deveria importar. Você simplesmente não pode usar a .notação com todas essas propriedades. A notação de colchetes funciona com qualquer string.
Ben McCormick
2
Realmente funciona muito bem. Estou usando com êxito esta solução (a 'específica') para alterar as notações numéricas em inglês para europeias (24.973,56 a 24,973,56), usando map={'.': ',', ',': '.'}e regex /\.|,/g.
Sygmoral
5
Eu amo essa solução, mas precisei substituir return mapObj[matched.toLowerCase()];apenas return mapObj[matched];uma vez que uso chaves com distinção entre maiúsculas e minúsculas mapObj.
Michal Moravcik
2
Você pode querer escapar das chaves para a expressão regular: Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'). Inspirado por esta resposta
robsch 16/07/19
9

Isso pode não atender à sua necessidade exata neste caso, mas achei uma maneira útil de substituir vários parâmetros em strings, como uma solução geral. Ele substituirá todas as instâncias dos parâmetros, não importa quantas vezes eles sejam referenciados:

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

Você o chamaria da seguinte maneira:

var person = '{title} {first} {last}'.fmt({ title: 'Agent', first: 'Jack', last: 'Bauer' });
// person = 'Agent Jack Bauer'
Iian
fonte
8

Use itens numerados para evitar a substituição novamente. por exemplo

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

então

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

Como funciona: -% \ d + localiza os números que vêm após um%. Os colchetes capturam o número.

Esse número (como uma string) é o segundo parâmetro, n, da função lambda.

O + n-1 converte a string no número e 1 é subtraído para indexar a matriz de animais de estimação.

O número% é então substituído pela string no índice da matriz.

O / g faz com que a função lambda seja chamada repetidamente com cada número que é substituído por uma sequência da matriz.

No JavaScript moderno: -

replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])
Quentin 2
fonte
Interessante. Você pode explicar a lógica na função de substituição?
precisa saber é o seguinte
5

Isso funcionou para mim:

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"
João Paulo
fonte
Não funciona se a sequência contiver caracteres regex.
Roemer
Sobre "não estenda ...": estendi minha String para comparar duas strings para igualdade, sem distinção entre maiúsculas e minúsculas. Essa funcionalidade não é fornecida pelo String, mas pode ser um dia, o que pode causar a quebra de meus aplicativos. Existe uma maneira de "subclasse" ou "estender" String para incluir essa função com segurança ou devo simplesmente definir uma nova função de dois argumentos como parte da minha biblioteca de aplicativos?
David Spector
4

usando 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)

Exemplo

// /////////////    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
fonte
Melhor resposta. Mas existe uma razão para usar, em ${f}vez de f, para o valor acumulado?
David Spector
1
Se você deseja que TODAS as seqüências de caracteres especificadas sejam substituídas, não apenas a primeira, adicione o sinalizador g: "const result1 = arrayOfObjects.reduce ((f, s) => ${f}.replace (new RegExp (Object.keys (s) [ 0], 'g'), s [Object.keys (s) [0]]), frase1) "
David Spector
2

Caso alguém esteja se perguntando por que a solução do pôster original não está funcionando:

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
fonte
ha ha ... bem analisado ... thumbsup
Deepa MG
1

função regular do usuário para definir o padrão a ser substituído e, em seguida, use a função de substituição para trabalhar na sequência de entrada,

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');
KARTHIKEYAN.A
fonte
Se você não souber, pule, mas não diga que é a resposta errada. Meu caso "{" a ": 1," b ": 2}" é assim que eu usei para substituir a maneira acima. Se isso ajuda os outros, se eles querem outros, a resposta não é apenas para você. @Carr
KARTHIKEYAN.A
Mais uma vez, você só forneceu uma resposta sem sentido, o que você faz é o autor da questão já pode fazer na pergunta, esta resposta vai enganar as pessoas que eles podem pensar nova e utilizar o RegExpobjeto poderia resolver o problema
Carr
Nesse caso, você ainda tem o mesmo problema que a pergunta de quem pergunta quando você faz #var i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
277 Carr Carr
1

Com o meu pacote de substituição única , você pode fazer o seguinte:

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
fonte
Este pacote é incrível :) Funciona exatamente como eu esperava
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
fonte
3
O OP perguntou "É possível substituir várias strings por várias outras strings ao mesmo tempo ". Este é três etapas separadas.
LittleBobbyTables - Au Revoir
1

Você pode encontrar e substituir a string usando 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
fonte
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 seqüências de caracteres que leva, quantos argumentos quisermos e substitui todos eles pelo último argumento que especificamos 2013 CopyRights salvos para: Max Ahmed, este é um exemplo:

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
fonte
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
fonte
0

Eu escrevi este pacote npm stringinject https://www.npmjs.com/package/stringinject que permite que você faça o seguinte

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

que substituirá {0} e {1} pelos itens da matriz e retornará a seguinte string

"this is a test string for stringInject"

ou você pode substituir espaços reservados por chaves e valores de objetos da seguinte maneira:

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

"My username is tjcafferkey on Github" 
tjcafferkey
fonte
0

Você pode usar https://www.npmjs.com/package/union-replacer para essa finalidade. É basicamente uma string.replace(regexp, ...)contrapartida, que permite que várias substituições ocorram em uma única passagem, preservando a potência total destring.replace(...) .

Divulgação: Eu sou o autor. A biblioteca foi desenvolvida para oferecer suporte a substituições mais complexas configuráveis ​​pelo usuário e aborda todas as questões problemáticas, como grupos de captura, referências anteriores e substituições de funções de retorno de chamada.

As soluções acima são boas o suficiente para substituições exatas de cordas.

Martin Čížek
fonte
-1

Expandi um pouco o @BenMcCormicks. Ele trabalhou para cordas regulares, mas não se eu tivesse escapado de caracteres ou curingas. Aqui está o que eu fiz

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)

retorna "blá blá 234433 blá blá"

Dessa forma, ele corresponderá à chave no mapObj e não à palavra correspondente '

Drew Landgrave
fonte
// inútil: replaceAll ("Eu tenho um gato, um cachorro e uma cabra.", {cat: "dog", cachorro: "cabra", cabra: "gato"}) // produz: "Eu tenho um gato , um gato e um gato ".
Devon
-3

Solução com o Jquery (primeiro inclua este arquivo): Substitua várias strings por várias outras strings:

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));
    });
});
Super Model
fonte
Esta solução requer JQuery?
Anderson Green
tag javascript adicionada em questão, e jquery é uma biblioteca de javascript.
Super Model
2
@Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm, a lógica está desativada, deve ser o contrário, e também apenas um aviso - a partir das informações da tag javascript: " A menos que outra tag para uma estrutura / biblioteca também esteja incluída, é esperada uma resposta JavaScript pura. "
Traxo
@ Anderson Green, sim jquery necessário para o script acima.
Super Model
@ Traxo, na maioria das aplicações web estamos usando framework (bootstrap / material do google). Jquery inclui em todas as estruturas modernas. Portanto, jquery é um item necessário para aplicativos da web.
Super