Remplacer plusieurs chaînes par plusieurs autres chaînes

213

J'essaie de remplacer plusieurs mots d'une chaîne par plusieurs autres mots. La chaîne est «J'ai un chat, un chien et une chèvre».

Cependant, cela ne produit pas "J'ai un chien, une chèvre et un chat", mais cela produit plutôt "J'ai un chat, un chat et un chat". Est-il possible de remplacer plusieurs chaînes par plusieurs autres chaînes en même temps en JavaScript, afin que le résultat correct soit produit?

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
la source
Je veux remplacer plusieurs mots d'une chaîne par plusieurs autres mots, sans remplacer les mots qui ont déjà été remplacés.
Anderson Green
j'ai une requête différente, que se passe-t-il si je ne sais pas que l'utilisateur va entrer un chat ou un chien ou une chèvre (cela vient au hasard) mais chaque fois que ce genre de mot viendra, je dois le remplacer par disons `` animal ''. comment obtenir ce scénario
Prasanna Sasne

Réponses:

445

Solution spécifique

Vous pouvez utiliser une fonction pour remplacer chacun d'eux.

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

exemple jsfiddle

La généraliser

Si vous souhaitez maintenir dynamiquement l'expression régulière et simplement ajouter de futurs échanges à la carte, vous pouvez le faire

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

pour générer l'expression régulière. Alors ça ressemblerait à ça

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

Et pour ajouter ou modifier d'autres remplacements, vous pouvez simplement modifier la carte. 

violon avec regex dynamique

Rendre réutilisable

Si vous voulez que ce soit un modèle général, vous pouvez le retirer à une fonction comme celle-ci

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

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

Donc, vous pouvez simplement passer la str et une carte des remplacements que vous souhaitez à la fonction et cela retournera la chaîne transformée.

violon avec fonction

Pour garantir que Object.keys fonctionne dans les anciens navigateurs, ajoutez un polyfill, par exemple à partir de MDN ou Es5 .

Ben McCormick
la source
4
Je ne sais pas si je pourrais utiliser cette fonction pour remplacer tous les types de chaînes, car les caractères autorisés dans les chaînes JavaScript ne sont pas les mêmes que ceux autorisés dans les identificateurs JavaScript (tels que les clés utilisées ici) .
Anderson Green
2
vous pouvez utiliser une chaîne arbitraire comme propriété javascript. Ça ne devrait pas avoir d'importance. Vous ne pouvez tout simplement pas utiliser la .notation avec toutes ces propriétés. La notation entre parenthèses fonctionne avec n'importe quelle chaîne.
Ben McCormick
2
Cela fonctionne en effet très bien. J'utilise avec succès cette solution (la «spécifique») pour changer les notations numériques anglaises en européennes (24,973.56 à 24.973,56), en utilisant map={'.': ',', ',': '.'}et regex /\.|,/g.
Sygmoral
5
J'aime cette solution , mais je devais remplacer return mapObj[matched.toLowerCase()];juste return mapObj[matched];que j'utilise des clés cas sensibles mapObj.
Michal Moravcik
2
Vous pouvez échapper aux clés de l'expression régulière: Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'). Inspiré par cette réponse
robsch
9

Cela peut ne pas répondre à votre besoin exact dans ce cas, mais j'ai trouvé que c'était un moyen utile de remplacer plusieurs paramètres dans les chaînes, comme solution générale. Il remplacera toutes les instances des paramètres, quel que soit le nombre de fois où ils sont référencés:

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

Vous l'invoqueriez comme suit:

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

Utilisez des éléments numérotés pour éviter de les remplacer à nouveau. par exemple

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

puis

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

Comment ça marche: -% \ d + trouve les nombres qui viennent après un%. Les crochets capturent le nombre.

Ce nombre (sous forme de chaîne) est le deuxième paramètre, n, de la fonction lambda.

Le + n-1 convertit la chaîne en nombre puis 1 est soustrait pour indexer le tableau pets.

Le nombre% est ensuite remplacé par la chaîne à l'index du tableau.

Le / g provoque l'appel répété de la fonction lambda avec chaque numéro qui est ensuite remplacé par une chaîne du tableau.

En JavaScript moderne: -

replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])
Quentin 2
la source
Intéressant. Pouvez-vous expliquer la logique de la fonction de remplacement?
Eric Hepperle - CodeSlayer2010
5

Cela a fonctionné pour moi:

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
la source
Ne fonctionne pas si la chaîne contient des caractères d'expression régulière.
Roemer
A propos de "ne pas étendre ...": j'ai étendu ma chaîne pour comparer deux chaînes d'égalité, insensible à la casse. Cette fonctionnalité n'est pas fournie par String, mais elle pourrait l'être un jour, ce qui pourrait entraîner la rupture de mes applications. Existe-t-il un moyen de "sous-classe" ou "étendre" String pour inclure une telle fonction en toute sécurité, ou dois-je simplement définir une nouvelle fonction à deux arguments dans le cadre de ma bibliothèque d'applications?
David Spector
4

en utilisant 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)

Exemple

// /////////////    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
la source
Meilleure réponse. Mais y a-t-il une raison d'utiliser ${f}au lieu de f pour la valeur cumulée?
David Spector
1
Si vous souhaitez que TOUTES les chaînes données soient remplacées, pas seulement la première, ajoutez l'indicateur g: "const result1 = arrayOfObjects.reduce ((f, s) => ${f}.replace (new RegExp (Object.keys (s) [ 0], 'g'), s [Object.keys (s) [0]]), phrase1) "
David Spector
2

Juste au cas où quelqu'un se demanderait pourquoi la solution de l'affiche originale ne fonctionne pas:

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
la source
ha ha ... bien analysé ... thumbsup
Deepa MG
1

fonction régulière de l'utilisateur pour définir le modèle à remplacer, puis utiliser la fonction de remplacement pour travailler sur la chaîne d'entrée,

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');
KARTHIKEYAN.A
la source
Si vous ne savez pas sauter, mais ne dites pas que c'est la mauvaise réponse. Mon cas "{" a ": 1," b ": 2}" comme ça est là, j'ai utilisé pour remplacer la façon ci-dessus. Si cela aide les autres s'ils veulent pour les autres, la réponse n'est pas seulement pour vous. @Carr
KARTHIKEYAN.A
Encore une fois, vous venez de fournir une réponse dénuée de sens, ce que vous faites est que le demandeur peut déjà faire dans la question, cette réponse induira en erreur les gens qu'ils peuvent penser nouveaux et utiliser l' RegExpobjet pourrait résoudre le problème
Carr
Dans ce cas, vous avez toujours le même problème que la question du demandeur lorsque vous le faitesvar i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
Carr
1

Avec mon package à remplacement unique , vous pouvez effectuer les opérations suivantes:

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
la source
Ce package est incroyable :) Fonctionne exactement comme je
m'y
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
la source
3
L'OP a demandé "Est-il possible de remplacer plusieurs chaînes par plusieurs autres chaînes en même temps ". Il s'agit de trois étapes distinctes.
LittleBobbyTables - Au Revoir
1

Vous pouvez rechercher et remplacer une chaîne à l'aide de délimiteurs.

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
la source
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;
}

/ * méthode replaceSome pour les chaînes qu'il faut autant, autant d'arguments que nous voulons et les remplace tous par le dernier argument pour lequel nous avons spécifié 2013 CopyRights enregistré pour: Max Ahmed voici un exemple:

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
la source
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
la source
0

J'ai écrit ce package npm stringinject https://www.npmjs.com/package/stringinject qui vous permet de faire ce qui suit

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

qui remplacera les {0} et {1} par les éléments du tableau et renverra la chaîne suivante

"this is a test string for stringInject"

ou vous pouvez remplacer les espaces réservés par des clés d'objet et des valeurs comme ceci:

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

"My username is tjcafferkey on Github" 
tjcafferkey
la source
0

Vous pouvez utiliser https://www.npmjs.com/package/union-replacer à cet effet. Il s'agit essentiellement d'une string.replace(regexp, ...)contrepartie, qui permet à plusieurs remplacements de se produire en une seule passe tout en préservant la pleine puissance destring.replace(...) .

Divulgation: je suis l'auteur. La bibliothèque a été développée pour prendre en charge des remplacements configurables par l'utilisateur plus complexes et elle traite toutes les choses problématiques comme les groupes de capture, les références arrières et les remplacements de fonctions de rappel.

Les solutions ci-dessus sont cependant assez bonnes pour des remplacements de chaînes exacts.

Martin Čížek
la source
0

en utilisant la fonction prototype, nous pouvons remplacer facilement en passant un objet avec des clés et des valeurs et du texte remplaçable

String.prototype.replaceAll=function(obj,keydata='key'){
 const keys=keydata.split('key');
 return Object.entries(obj).reduce((a,[key,val])=> a.replace(`${keys[0]}${key}${keys[1]}`,val),this)
}

const data='hids dv sdc sd ${yathin} ${ok}'
console.log(data.replaceAll({yathin:12,ok:'hi'},'${key}'))

Yathiŋ K Rào
la source
-1

J'ai développé un peu @BenMcCormicks. Il travaillait pour des cordes régulières mais pas si j'avais échappé à des caractères ou à des caractères génériques. Voici ce que j'ai fait

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)

renvoie "bla bla 234433 bla bla"

De cette façon, il correspondra à la clé dans mapObj et non au mot correspondant '

Drew Landgrave
la source
// sans valeur: replaceAll ("J'ai un chat, un chien et une chèvre.", {cat: "chien", chien: "chèvre", chèvre: "chat"}) // produit: "J'ai un chat , un chat et un chat. "
devon
-3

Solution avec Jquery (incluez d'abord ce fichier): remplacez plusieurs chaînes par plusieurs autres chaînes:

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 modèle
la source
Cette solution nécessite-t-elle JQuery?
Anderson Green
balise javascript ajoutée en question, et jquery est une bibliothèque de javascript.
Super Model
2
@Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm que la logique est désactivée, cela devrait être l'inverse, et aussi juste un avertissement - à partir des informations de balise javascript: " À moins qu'une autre balise pour un framework / bibliothèque soit également incluse, une réponse JavaScript pure est attendue. "
Traxo
@Anderson Green, oui jquery nécessaire pour le script ci-dessus.
Super Model
@ Traxo, dans la plupart des applications Web, nous utilisons un framework (matériel bootstrap / google). Jquery inclut dans tous les cadres modernes. Ainsi, jquery est un élément nécessaire pour les applications Web.
Super Model