Zamień wiele ciągów na wiele innych


213

Próbuję zastąpić wiele słów w ciągu wieloma innymi słowami. Sznurek brzmi: „Mam kota, psa i kozę”.

Nie powoduje to jednak: „Mam psa, kozę i kota”, ale zamiast tego daje „Mam kota, kota i kota”. Czy w JavaScript można zastąpić wiele ciągów jednocześnie wieloma innymi ciągami, aby uzyskać poprawny wynik?

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".

Chcę zastąpić wiele słów w ciągu wieloma innymi słowami bez zastępowania słów, które zostały już zastąpione.
Anderson Green

mam inne zapytanie, co jeśli nie wiem, czy użytkownik wprowadzi kota, psa lub kozę (to losowo nadchodzi), ale ilekroć pojawi się to słowo, muszę je zastąpić, powiedzmy „zwierzę”. jak uzyskać ten scenariusz
Prasanna Sasne

Odpowiedzi:


445

Konkretne rozwiązanie

Możesz użyć funkcji, aby zastąpić każdą z nich.

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

przykład jsfiddle

Uogólniając to

Jeśli chcesz dynamicznie utrzymywać wyrażenie regularne i po prostu dodawać przyszłe wymiany do mapy, możesz to zrobić

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

wygenerować wyrażenie regularne. Więc to wyglądałoby tak

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

Aby dodać lub zmienić więcej zamienników, wystarczy edytować mapę. 

skrzypce z dynamicznym wyrażeniem regularnym

Dzięki temu jest wielokrotnego użytku

Jeśli chcesz, aby był to ogólny wzorzec, możesz wyciągnąć to do takiej funkcji

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

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

Więc możesz po prostu przekazać str i mapę zamienników, które chcesz do funkcji, i zwróci transformowany ciąg.

skrzypce z funkcją

Aby upewnić się, że Object.keys działa w starszych przeglądarkach, dodaj polifill np. Z MDN lub Es5 .


4
Nie jestem pewien, czy mógłbym użyć tej funkcji do zastąpienia wszystkich typów ciągów, ponieważ znaki dozwolone w ciągach JavaScript nie są takie same jak znaki dozwolone w identyfikatorach JavaScript (takie jak używane tutaj klucze) .
Anderson Green

2
możesz użyć dowolnego ciągu jako właściwości javascript. Nie powinno mieć znaczenia. Po prostu nie możesz używać .notacji ze wszystkimi takimi właściwościami. Notacja w nawiasach działa na dowolnym łańcuchu.
Ben McCormick

2
Rzeczywiście działa świetnie. Z powodzeniem używam tego rozwiązania („specyficznego”) do zmiany notacji liczb angielskich na europejskie (24 973,56 na 24,973,56), używając map={'.': ',', ',': '.'}i regex /\.|,/g.
Sygmoral,

5
Kocham to rozwiązanie, ale musiałem wymienić return mapObj[matched.toLowerCase()];tylko return mapObj[matched];ponieważ używam klawiszy czułych Sprawa w mapObj.
Michal Moravcik,

2
Może chcesz uciec klucze do wyrażenia regularnego: Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'). Zainspirowany tą odpowiedzią
robsch

9

W tym przypadku może to nie zaspokajać dokładnie Twojej potrzeby, ale znalazłem przydatny sposób na zastąpienie wielu parametrów w ciągach, jako ogólne rozwiązanie. Zastąpi wszystkie wystąpienia parametrów, bez względu na to, ile razy są do nich odniesienia:

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

Wywołalibyście to w następujący sposób:

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

8

Użyj ponumerowanych elementów, aby zapobiec wymianie. na przykład

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

następnie

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

Jak to działa: -% \ d + znajduje liczby, które występują po%. Nawiasy przechwytują liczbę.

Ta liczba (jako ciąg znaków) jest drugim parametrem, n, funkcji lambda.

+ N-1 konwertuje ciąg na liczbę, a następnie 1 jest odejmowany w celu zindeksowania tablicy zwierzaków.

Liczba% jest następnie zastępowana ciągiem o indeksie tablicowym.

/ G powoduje, że funkcja lambda jest wywoływana wielokrotnie z każdą liczbą, która jest następnie zastępowana łańcuchem z tablicy.

W nowoczesnym JavaScript: -

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

Ciekawy. Czy potrafisz wyjaśnić logikę w funkcji zamiany?
Eric Hepperle - CodeSlayer2010

5

To działało dla mnie:

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"


Nie działa, jeśli ciąg zawiera znaki regularne.
Roemer

O „nie przedłużaj ...”: Rozszerzyłem mój ciąg, aby porównać dwa ciągi znaków dla równości, bez rozróżniania wielkości liter. Ta funkcja nie jest zapewniana przez String, ale może kiedyś pewnego dnia spowodować awarię moich aplikacji. Czy istnieje sposób na „podklasę” lub „rozszerzenie” ciągu znaków w celu bezpiecznego włączenia takiej funkcji, czy też powinienem po prostu zdefiniować nową funkcję dwóch argumentów jako część mojej biblioteki aplikacji?
David Spector,

4

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

Przykład

// /////////////    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


Najlepsza odpowiedź. Ale czy istnieje powód, aby użyć ${f}f zamiast wartości kumulacyjnej?
David Spector,

1
Jeśli chcesz zastąpić WSZYSTKIE podane ciągi, a nie tylko pierwsze, dodaj flagę g: "const result1 = arrayOfObjects.reduce ((f, s) => ${f}.replace (new RegExp (Object.keys (s) [ 0], „g”), s [Object.keys (s) [0]]), zdanie 1) ”
David Spector,

2

Na wypadek, gdyby ktoś zastanawiał się, dlaczego oryginalne rozwiązanie plakatu nie działa:

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."

ha ha ... dobrze przeanalizowane ... thumbsup
Deepa MG

1

zwykła funkcja użytkownika, aby zdefiniować wzorzec do zamiany, a następnie użyć funkcji replace do pracy na ciągu wejściowym,

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');

Jeśli nie wiesz, pomiń, ale nie mów, że to zła odpowiedź. Mój przypadek „{” a ”: 1,„ b ”: 2}” taki jak tam, użyłem go, aby zastąpić powyższy sposób. Jeśli to pomaga innym, jeśli chcą dla innych, odpowiedź nie jest tylko dla ciebie. @Crr
KARTHIKEYAN.A

Ponownie, po prostu podałeś bezsensowną odpowiedź, to, co robisz, to pytanie, które pytający może już zrobić w pytaniu, ta odpowiedź wprowadzi ludzi w błąd, że mogą pomyśleć o nowym, a wykorzystanie RegExpobiektu może rozwiązać problem
Carr

W takim przypadku nadal masz ten sam problem, co pytanie zadawane przez pytającegovar i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
Carr

1

Z moim pakietem „ zamień raz” możesz wykonać następujące czynności:

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.'

Ten pakiet jest niesamowity :) Działa dokładnie tak, jak się spodziewałem
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."

3
OP pytanie „Czy możliwe jest zastąpienie wielu ciągów z wielu innych strun jednocześnie ”. To trzy oddzielne kroki.
LittleBobbyTables - Au Revoir

1

Możesz znaleźć i zastąpić ciąg za pomocą ograniczników.

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


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 metoda na ciągi, które pobiera, tyle argumentów, ile chcemy i zamienia je wszystkie na ostatni argument, który podaliśmy 2013 CopyRights zapisane dla: Max Ahmed to jest przykład:

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/


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>

0

Napisałem ten pakiet npm stringinject https://www.npmjs.com/package/stringinject, który pozwala wykonać następujące czynności

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

który zastąpi {0} i {1} elementami tablicy i zwróci następujący ciąg

"this is a test string for stringInject"

lub możesz zastąpić symbole zastępcze kluczami i wartościami obiektów takimi jak:

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

"My username is tjcafferkey on Github" 

0

W tym celu możesz użyć https://www.npmjs.com/package/union-replacer . Jest to w zasadzie string.replace(regexp, ...)odpowiednik, który pozwala na wielokrotne zastępowanie w jednym przejściu przy jednoczesnym zachowaniu pełnej mocystring.replace(...) .

Ujawnienie: Jestem autorem. Biblioteka została opracowana w celu obsługi bardziej złożonych, konfigurowanych przez użytkownika zamienników i rozwiązuje wszystkie problematyczne rzeczy, takie jak grupy przechwytywania, odwołania wsteczne i zamiany funkcji zwrotnych.

Powyższe rozwiązania są jednak wystarczające do dokładnej zamiany łańcucha.


-1

Rozbudowałem trochę @BenMcCormicks. Pracował dla zwykłych strun, ale nie, gdybym unikał znaków lub symboli wieloznacznych. Oto co zrobiłem

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)

zwraca „bla bla 234433 bla bla”

W ten sposób dopasuje klucz do mapObj, a nie dopasowane słowo „


// bezwartościowe: replaceAll („Mam kota, psa i kozę”., {cat: „pies”, pies: „koza”, koza: „kot”}) // produkuje: „Mam kota , kot i kot ”.
devon,

-3

Rozwiązanie z Jquery (najpierw dołącz ten plik): Zamień wiele ciągów na wiele innych:

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

Czy to rozwiązanie wymaga JQuery?
Anderson Green

dodany tag javascript, a jquery jest biblioteką javascript.
Super Model,

2
@ Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm, że logika jest wyłączona, powinna być odwrotna , a także tylko heads-up - z informacji o tagach javascript: „ O ile nie jest zawarty inny tag dla frameworka / biblioteki, należy oczekiwać czystej odpowiedzi JavaScript.
Traxo

@Anderson Green, tak jquery potrzebne do powyższego skryptu.
Super Model

@ Traxo, w większości aplikacji internetowych korzystamy z frameworka (bootstrap / google). Jquery obejmuje wszystkie nowoczesne ramy. Zatem jquery jest niezbędnym elementem dla aplikacji internetowych.
Super Model,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.