Jak zamienić wszystkie wystąpienia ciągu?


4376

Mam ten ciąg:

"Test abc test test abc test test test abc test test abc"

Robić:

str = str.replace('abc', '');

wydaje się, że usuwa tylko pierwsze wystąpienie abcpowyższego ciągu.

Jak mogę zastąpić wszystkie jego wystąpienia?


5
Przy wymianie wszystkich wystąpień abaw ababaz ca, skutkujących można się spodziewać? caba? abca? cca?
— reinierpost

String.prototype.replaceAll()dostarczany w Safari 13.1 i teraz w Firefox Nightly oraz Chrome Dev i Canary i będzie dostępny w Firefox 77 i Chrome 85. Nie jest jeszcze udokumentowany w MDN, ale github.com/tc39/proposal-string-replaceall#high-level-api ma wyjaśnienie: „Jeśli searchValue jest ciągiem, String.prototype.replaceAllzastępuje wszystkie wystąpienia searchValue (tak jakby .split(searchValue).join(replaceValue)lub użyto globalnego i poprawnie zmienionego wyrażenia regularnego). Jeśli searchValue jest nieglobalnym wyrażeniem regularnym, String.prototype.replaceAllzgłasza wyjątek ”
— sideshowbarker

Odpowiedzi:


1605

Uwaga: Nie używaj tego w kodzie krytycznym dla wydajności.

Jako alternatywę dla wyrażeń regularnych dla prostego ciągu literalnego możesz użyć

str = "Test abc test test abc test...".split("abc").join("");

Ogólny wzór to

str.split(search).join(replacement)

W niektórych przypadkach było to szybsze niż używanie replaceAlli wyrażenie regularne, ale wydaje się, że nie jest tak już w nowoczesnych przeglądarkach.

Benchmark: https://jsperf.com/replace-all-vs-split-join

Wniosek: jeśli masz krytyczny przypadek użycia (np. Przetwarzanie setek ciągów znaków), użyj metody Regexp. Ale w najbardziej typowych przypadkach użycia nie warto martwić się o znaki specjalne.


147
Zaskoczyło mnie to, ponieważ spodziewałbym się, że ta metoda przydziela więcej obiektów, tworzy więcej śmieci, a tym samym zajmuje więcej czasu, ale kiedy faktycznie testowałem w przeglądarce, ta metoda była konsekwentnie o około 20% szybsza niż zaakceptowana odpowiedź. Oczywiście wyniki mogą się różnić.
— MgSam

42
Byłem ciekawy i skonfigurowałem to: jsperf.com/replace-all-vs-split-join . Wygląda na to, że v8 jest po prostu szalenie szybkie w dzieleniu / łączeniu tablic w porównaniu do innych silników javascript.
— fabi

8
Bardzo fajnie - oszczędza również możliwość złych RegExps przy przekazywaniu znaków specjalnych. Dodaję ogólną flagę „znajdź i zamień” we właściwości obiektu, ale martwiłem się, czy musiałem zamienić „.” lub „}” i zapomniałem, że korzystam z RegEx 3 miesiące później!
— tobriand

9
I jak String.prototype: String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}. Użycie: "My string".replaceAll('st', '');tworzy „Mój pierścień”
— MacroMan

8
Nie widzę powodu, dla którego ostrzeżenie nie wykorzystuje tego w produkcji. To nie jest więcej hack niż ucieczka przed wyrażeniem regularnym tylko dlatego, że chcesz zastąpić wiele wystąpień, ale w ogóle nie potrzebujesz wyrażenia regularnego. Po prostu zawiń ten tak zwany „hack” w przyjemną replaceAllfunkcję, a stanie się on tak samo czytelny jak wszystko inne. Ponieważ wydajność nie jest zła, nie ma powodu, aby unikać tego rozwiązania.
— Youen

4383
str = str.replace(/abc/g, '');

W odpowiedzi na komentarz:

var find = 'abc';
var re = new RegExp(find, 'g');

str = str.replace(re, '');

W odpowiedzi na komentarz Click Upvote możesz uprościć go jeszcze bardziej:

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(find, 'g'), replace);
}

Uwaga: Wyrażenia regularne zawierają znaki specjalne (meta) i dlatego niebezpieczne jest ślepe przekazywanie argumentu w findpowyższej funkcji bez wstępnego przetwarzania go w celu ucieczki od tych znaków. To jest pokryta w Mozilla Developer Network „s JavaScript przewodnika po wyrażeń regularnych , gdzie prezentują oni następującą funkcję użytkową (co zmieniło się co najmniej dwa razy, ponieważ ta odpowiedź została pierwotnie napisana, więc upewnij się, aby sprawdzić na stronie MDN dla potencjalnych aktualizacji):

function escapeRegExp(string) {
  return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

Aby więc uczynić replaceAll()powyższą funkcję bezpieczniejszą, można ją zmodyfikować w następujący sposób escapeRegExp:

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

4
Wyrażenia regularne są jedynym sposobem na osiągnięcie tego „od razu po wyjęciu z pudełka” bez implementacji własnej metody „replaceAll”. Nie sugeruję ich używania tylko ze względu na ich użycie.
— Sean Bright,

10
To jest moja własna funkcja z tego komentarza: function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; }
— Kliknij Upvote

47
Głównym zastrzeżeniem replaceAllimplementacji jest to, że nie będzie działać, jeśli findzawiera metaznaki.
— Martin Ender

1
@SeanBright masz rację. Użyłem twojego javascript w kodzie php, więc musiałem dodać dodatkowy ukośnik odwrotny, aby uciec. Na skrzypcach Twój kod jest idealny. Powinienem był sprawdzić. Przeprosiny jsfiddle.net/7y19xyq8
— Onimusha


2437

Ze względu na kompletność, pomyślałem o tym, której metody powinienem to zrobić. Istnieją zasadniczo dwa sposoby wykonania tego, jak sugerują inne odpowiedzi na tej stronie.

Uwaga: Ogólnie rzecz biorąc, rozszerzenie wbudowanych prototypów w JavaScript zwykle nie jest zalecane. Jako rozszerzenie przedstawiam prototyp String w celach ilustracyjnych, pokazując różne implementacje hipotetycznej standardowej metody Stringwbudowanego prototypu.


Implementacja oparta na wyrażeniach regularnych

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

Implementacja Split and Join (funkcjonalna)

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

Nie wiedząc zbyt wiele o tym, jak wyrażenia regularne działają za kulisami pod względem wydajności, miałem tendencję do skłaniania się do podziału i przyłączania się do implementacji w przeszłości, nie myśląc o wydajności. Kiedy zastanawiałem się, która jest bardziej wydajna i przy jakim marginesie, wykorzystałem ją jako pretekst, aby się dowiedzieć.

Na moim komputerze z Chrome Windows 8 implementacja oparta na wyrażeniach regularnych jest najszybsza , a implementacja podziału i łączenia jest o 53% wolniejsza . Oznacza to, że wyrażenia regularne są dwa razy szybsze dla zastosowanego wejścia lorem ipsum.

Sprawdź ten test porównawczy między tymi dwoma implementacjami.


Jak zauważono w komentarzu poniżej autorstwa @ThomasLeduc i inni, może występować problem z implementacją opartą na wyrażeniach regularnych, jeśli searchzawiera pewne znaki, które w wyrażeniach regularnych są zastrzeżone jako znaki specjalne . Implementacja zakłada, że ​​program wywołujący będzie wcześniej uciekał z ciągu lub przekaże tylko ciągi, które nie zawierają znaków w tabeli w wyrażeniach regularnych (MDN).

MDN zapewnia również implementację pozwalającą uniknąć naszych ciągów. Byłoby miło, gdyby to również zostało znormalizowane jako RegExp.escape(str), ale niestety nie istnieje:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

Moglibyśmy wywoływać escapeRegExpw ramach naszej String.prototype.replaceAllimplementacji, jednak nie jestem pewien, jak bardzo wpłynie to na wydajność (potencjalnie nawet dla ciągów, dla których ucieczka nie jest potrzebna, jak wszystkie ciągi alfanumeryczne).


8
W Androidzie 4.1 metoda regexp jest 15% szybsza, ale nie uciekasz przed wyrażeniem, aby wyszukać, więc ten test porównawczy jest niepełny.
— andreszs,

33
Wystąpił problem z tym rozwiązaniem, jeśli szukany ciąg znaków zawiera znaki specjalne wyrażenia regularnego, zostaną one zinterpretowane. Polecam odpowiedź @Sandy Unitedwolf.
— Thomas Leduc

2
Pierwszy zrobi to: 'bla.bla'.replaceAll ('. ',' _ '); „_______”. Drugi zrobi „bla_bla”, co jest bardziej ogólnie tym, co chcesz zrobić.
— RobKohr

1
@ThomasLeduc wygląda na to, że problem, o którym wspomniałeś, można obejść za pomocą lodash => lodash.com/docs/4.17.5#escapeRegExp
— Matthew Beck

1
Pozostawienie tego tutaj przyszłym widzom, którzy również zastanawiają się, dlaczego rozszerzenie natywnego obiektu jest złym pomysłem: stackoverflow.com/questions/14034180/…
— Ben Cooper

690

Użycie wyrażenia regularnego z gustawioną flagą zastąpi wszystkie:

someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"

Zobacz także tutaj


15
Myślę, że to trochę głupie, ale globalny regex JS jest jedynym sposobem na wielokrotne zastępowanie.
— Mike

5
technicznie rzecz biorąc, możesz zapętlić var sourceTextliczenie liczby wystąpień ( numOfInstances) za pomocą substringlub podzielić i policzyć długość (między innymi strategiami) thatWhichYouWantToReplacenastępnie wykonaj for (var i = 0; i < numOfInstances; i++){ sourceText = sourceText.replace('thatWhichYouWantToReplace', '');} lub nawet łatwiej po prostu użyj pętli while ( while sourceText.indexOf(thatWhichYouWantToReplace > -1){ sourceText = sourceText.replace(...)), ale nie rozumiem, dlaczego chcesz rób to w ten sposób, gdy korzystanie /gjest tak łatwe i prawdopodobnie bardziej wydajne.
— Zargold,

@Zargold Chciałbyś zrobić pętlę, aby upewnić się, że nawet po wymianie zastąpiłeś wszystkie instancje, co jest dość powszechną gotcha. Zobacz moją odpowiedź poniżej stackoverflow.com/a/26089052/87520
— SamGoody

109

Oto funkcja prototypu łańcucha w oparciu o przyjętą odpowiedź:

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

EDYTOWAĆ

Jeśli twoja findwola zawiera znaki specjalne, musisz uciec przed nimi:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
};

Fiddle: http://jsfiddle.net/cdbzL/


5
Ale co, jeśli findzawiera znaki podobne .lub $mające specjalne znaczenie w wyrażeniu regularnym?
— callum

1
@callum W takim przypadku musiałbyś uciec ze swojej zmiennej find (patrz edycja powyżej).
— jesal


jesal, jest to wspaniałe rozwiązanie napotkanego problemu zamiany napisów i najwyraźniej przezwycięża „niezmienność” napisów w JavaScript. Czy mógłbyś ty lub ktoś inny wyjaśnić, w jaki sposób ta prototypowa funkcja zastępuje niezmienność ciągów? To czyni pracę; Chcę tylko zrozumieć to dodatkowe pytanie, jakie się z tym wiąże.
— Tom

1
@Tom: W ogóle nie pokonuje niezmienności: var str = thistworzy drugie odwołanie do niezmiennego łańcucha, do którego replacestosowana jest metoda, co z kolei zwraca nowy niezmienny ciąg . te prototypowe funkcje zwracają nowy niezmienny ciąg, jeśli nie, będziesz w stanie pisać someStrVar.replaceAll('o', '0');i someStrVarzostałby zmieniony. Zamiast tego musisz napisać someStrVar = someStrVar.replaceAll('o', '0');<- ponownie przypisać, aby ustawić var, aby przechowywał nowy niezmienny ciąg . nie można tego obejść. Spróbuj w konsoli:x = 'foobar'; x.replaceAll('o', '0'); x;
— Elias Van Ootegem,

87

Aktualizacja:

Jest nieco późno na aktualizację, ale ponieważ natknąłem się na to pytanie i zauważyłem, że moja poprzednia odpowiedź nie jest tym, z którego jestem zadowolony. Ponieważ pytanie dotyczyło zamiany jednego słowa, to niewiarygodne, że nikt nie pomyślał o użyciu granic słów ( \b)

'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"

Jest to proste wyrażenie regularne, które w większości przypadków pozwala uniknąć zamiany części słów. Jednak myślnik -jest nadal uważany za granicę słów. Dlatego w tym przypadku można zastosować warunki warunkowe, aby uniknąć zamiany ciągów takich jak cool-cat:

'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"

w zasadzie to pytanie jest takie samo jak tutaj: JavaScript zamień „” na „” „”

@ Mike, sprawdź odpowiedź, której tam udzieliłem ... wyrażenie regularne nie jest jedynym sposobem na zastąpienie wielu wystąpień subskrypcji. Myśl elastycznie, myśl podziel!

var newText = "the cat looks like a cat".split('cat').join('dog');

Ewentualnie, aby zapobiec zamianie części słów - co zrobi również zatwierdzona odpowiedź! Można obejść ten problem za pomocą wyrażeń regularnych, które, przyznaję, są nieco bardziej złożone i jako rezultat tego są też nieco wolniejsze:

var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");

Dane wyjściowe są takie same, jak zaakceptowana odpowiedź, przy użyciu wyrażenia / cat / g na tym ciągu:

var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ?? 

Ups, to chyba nie jest to, czego chcesz. Czym więc jest? IMHO, regex, który warunkowo zastępuje „cat”. (tj. nie jest częścią słowa), tak jak:

var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"

Domyślam się, że to odpowiada twoim potrzebom. Oczywiście nie jest to w pełni odporne, ale powinno wystarczyć, aby zacząć. Polecam przeczytać więcej na tych stronach. Przyda się to w udoskonaleniu tego wyrażenia, aby spełnić Twoje specyficzne potrzeby.

http://www.javascriptkit.com/jsref/regexp.shtml

http://www.regular-expressions.info


Ostateczne dodanie:

Biorąc pod uwagę, że to pytanie wciąż ma wiele wyświetleń, pomyślałem, że mogę dodać przykład .replaceużycia z funkcją wywołania zwrotnego. W tym przypadku radykalnie upraszcza to wyrażenie i zapewnia jeszcze większą elastyczność, na przykład zastępując poprawną pisownię wielkimi literami lub zastępując jedno cati drugie catsza jednym razem:

'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
   .replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
    {
       //check 1st, capitalize if required
       var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
       if (char1 === ' ' && char2 === 's')
       {//replace plurals, too
           cat = replacement + 's';
       }
       else
       {//do not replace if dashes are matched
           cat = char1 === '-' || char2 === '-' ? cat : replacement;
       }
       return char1 + cat + char2;//return replacement string
    });
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar

Myślę, że dodatkowa interesująca część powinna zostać umieszczona na dole. ps .: Właśnie zauważyłem, że połowa pierwszej linii jest poza obszarem, pozwól mi to naprawić!

69

Dopasuj do globalnego wyrażenia regularnego:

anotherString = someString.replace(/cat/g, 'dog');

60

Aby zastąpić jednorazowe użycie:

var res = str.replace('abc', "");

Aby wymienić wiele razy, użyj:

var res = str.replace(/abc/g, "");

jeśli ktoś musi wymienić \ n, możesz to zrobić w następujący sposób:replace(/\n/g, '<br/>')
— Phan Van Linh

58

Są to najbardziej popularne i czytelne metody.

var str = "Test abc test test abc test test test abc test test abc"

Metoda 1:

str = str.replace(/abc/g, "replaced text");

Metoda 2:

str = str.split("abc").join("replaced text");

Metoda 3:

str = str.replace(new RegExp("abc", "g"), "replaced text");

Metoda 4:

while(str.includes("abc")){
    str = str.replace("abc", "replaced text");
}

Wynik:

console.log(str);
// Test replaced text test test replaced text test test test replaced text test test replaced text

44
str = str.replace(/abc/g, '');

Lub wypróbuj tutaj funkcję replaceAll:

Jakie są użyteczne metody JavaScript, które rozszerzają wbudowane obiekty?

str = str.replaceAll('abc', ''); OR

var search = 'abc';
str = str.replaceAll(search, '');

EDYCJA: Wyjaśnienie dotyczące zastępowania Wszystkie dostępne

Metoda „replaceAll” została dodana do prototypu String. Oznacza to, że będzie dostępny dla wszystkich ciągów znaków / literałów.

Na przykład

var output = "test this".replaceAll('this', 'that');  //output is 'test that'.
output = output.replaceAll('that', 'this'); //output is 'test this'

2
Czy możesz przepisać funkcję replaceAll () dla tych, którzy nie używają prototypu?
— Kliknij Upvote

@ Kliknij Upvote .... używasz prototypu, jest on częścią wszystkich obiektów JS. Myślę, że myślisz o bibliotece JS prototype.js.
— seth

seth, mała korekta. Jeśli dodasz metodę do prototypu, będzie ona dostępna dla wszystkich obiektów tego typu. Metodę replceAll dodano do prototypu String i powinna ona działać dla wszystkich obiektów String.
— SolutionYogi,

@solutionyogi - Tak, wcześniej używałem prototypu (poprawnie). Właśnie odniosłem się do komentarza OP o „nieużywaniu prototypu”, który, jak zakładam, miał na myśli Prototype.js (może niepoprawnie?). Powinienem powiedzieć „prototyp”, ponieważ próbowałem powiedzieć, że obiekty JavaScript mają prototyp. W związku z tym PO już „korzystał z prototypu”, choć w „pośredni” sposób. Pośrednie określenie może być niewłaściwe, ale jestem zmęczony, więc mea culpa.
— seth

41

Korzystanie RegExpz JavaScript może zrobić to za Ciebie, po prostu zrób coś takiego jak poniższy kod, nie zapomnij, /gpo czym wyróżnia się globalnie :

var str ="Test abc test test abc test test test abc test test abc";
str = str.replace(/abc/g, '');

Jeśli myślisz o ponownym użyciu, utwórz funkcję, która zrobi to za Ciebie, ale nie jest to zalecane, ponieważ jest to tylko funkcja jednego wiersza, ale ponownie, jeśli intensywnie z tego korzystasz, możesz napisać coś takiego:

String.prototype.replaceAll = String.prototype.replaceAll || function(string, replaced) {
  return this.replace(new RegExp(string, 'g'), replaced);
};

i po prostu używaj go w kodzie w kółko, jak poniżej:

var str ="Test abc test test abc test test test abc test test abc";
str = str.replaceAll('abc', '');

Ale jak wspomniałem wcześniej, nie zrobi to wielkiej różnicy pod względem wierszy, które mają być napisane, ani wydajności, tylko buforowanie funkcji może wpłynąć na szybsze działanie na długich ciągach, a także dobrą praktykę DRY kodu, jeśli chcesz ponownie użyć.


40

Powiedz, że chcesz zamienić wszystkie „abc” na „x”:

let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def

Próbowałem wymyślić coś prostszego niż modyfikacja prototypu łańcucha.


1
Prosta, łatwa i prawdopodobnie najbardziej wydajna opcja: ładna odpowiedź.
— machineghost

W rzeczywistości, chociaż nie przeprowadziłem osobnych pomiarów, podział / łączenie jest zwykle bardzo wydajnym rozwiązaniem.
— machineghost

1
jest nawet chromowany, 100% szybszy w Firefoxie i 50% wolniejszy w IE ...: jsperf.com/replace-regex-split-join
— Olivier


32

Zastępowanie pojedynczych cytatów:

function JavaScriptEncode(text){
    text = text.replace(/'/g,'&apos;')
    // More encode here if required

    return text;
}

2
Jak mogę zmienić drugą linię, aby zastąpić ciągi? To nie działa: text = text.replace ('hey', 'hello'); Dowolny pomysł?
— Stefan Đorđević

2
Jasne, Stefan, oto kod ... text = text.replace (/ hey / g, 'hello');
— Chris Rosete,

26

// zapętlić go, aż liczba wystąpień osiągnie wartość 0. LUB po prostu skopiuj / wklej

    function replaceAll(find, replace, str) 
    {
      while( str.indexOf(find) > -1)
      {
        str = str.replace(find, replace);
      }
      return str;
    }

23
Ta metoda jest niebezpieczna, nie używaj jej. Jeśli ciąg zastępujący zawiera słowo kluczowe wyszukiwania, nastąpi nieskończona pętla. Przynajmniej przechowuj wynik .indexOfw zmiennej i użyj tej zmiennej jako drugiego parametru .indexOf(minus długość słowa kluczowego plus długość ciągu zastępującego).
— Rob W

Zastanawiam się nad tym, aby najpierw zastąpić wzorzec wyszukiwania zużytym charakterem Unicode, ponieważ jesteśmy pewni, że nie jest on używany w ciągu wejściowym. Podobnie jak U + E000 w obszarze prywatnym. A następnie umieść go z powrotem w celu. Zbudowałem to tutaj. . Nie jestem pewien, czy to dobry pomysł.
— Lux

26
str = str.replace(new RegExp("abc", 'g'), "");

działało dla mnie lepiej niż powyższe odpowiedzi. więc new RegExp("abc", 'g')tworzy RegExp, który pasuje do wszystkich wystąpień ( 'g'flag) tekstu ( "abc"). Druga część jest zastąpiona pustym ciągiem ( ""). strjest łańcuchem i musimy go przesłonić, ponieważ replace(...)po prostu zwraca wynik, ale nie zastępuje. W niektórych przypadkach możesz chcieć tego użyć.


Ten fragment kodu może być rozwiązaniem, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu.
— yivi

Tak, masz rację. dodany. zredagowałem go również, aby odpowiedzieć na oryginalne pytanie :)
— csomakk

Uwaga: g flagi regex oznacza, że jest globalną flagę który będzie pasował do wszystkich wystąpień
— firstpostcommenter

25

To jest najszybsza wersja, która nie używa wyrażeń regularnych .

Zmieniono jsperf

replaceAll = function(string, omit, place, prevstring) {
  if (prevstring && string === prevstring)
    return string;
  prevstring = string.replace(omit, place);
  return replaceAll(prevstring, omit, place, string)
}

Jest prawie dwa razy szybszy niż metoda dzielenia i łączenia.

Jak wskazano w komentarzu tutaj, nie zadziała to, jeśli omitzmienna zawiera place, jak w:, replaceAll("string", "s", "ss")ponieważ zawsze będzie w stanie zastąpić inne wystąpienie tego słowa.

Jest inny jsperf z wariantami na mojej rekurencyjnej zamianie, które idą jeszcze szybciej ( http://jsperf.com/replace-all-vs-split-join/12 )!

  • Aktualizacja 27 lipca 2017 r .: Wygląda na to, że RegExp ma teraz najszybszą wydajność w niedawno wydanym Chrome 59.

Podobało mi się twoje rozwiązanie ... Chciałbym dać ci +10, ale oto moje +1. Myślę, że możesz zapisać indeks podciągu, który został zastąpiony i przejść do następnego, jeśli dopasowanie zostanie znalezione przy niższym indeksie, aby uniknąć problemu z nieskończoną pętlą. Nie mogę komentować wydajności, ponieważ jej nie testowałem, ale to tylko moje 2 centy za ten kawałek doskonałości.
— Fr0zenFyr

@ fr0zenfyr jeśli chcesz sprawdzić, czy pominąć jest na miejscu (aby zapobiec nieskończonej pętli) można zrobić warunkowego jak if(place.replace(omit) === omit) {nie pasuje, więc jest bezpieczny w użyciu zastąpić pętla } else {Mecz więc użyć innej metody jak Split i dołączyć}
— Cole Lawrence

Hmm .. ale jaki jest sens łączenia dwóch rozwiązań? W każdym razie nie jestem fanem podejścia typu split / join .. dzięki za radę.
— Fr0zenFyr

@ Fr0zenFyr Wierzę, że celem połączenia tych dwóch rozwiązań byłoby wycofanie się z wolniejszej metody, jeśli nie można użyć szybszej (na przykład, gdy pętla byłaby nieskończona). Byłoby to więc bezpieczne zabezpieczenie zapewniające funkcjonalność z wydajnością, ale bez możliwości awarii.
— Cole Lawrence

@momomo jak wadliwe?
— SandRock,

24

Wydajność

Dzisiaj 27.12.2019 Przeprowadzam testy na macOS 10.13.6 (High Sierra) dla wybranych rozwiązań.

Wnioski

  • str.replace(/abc/g, '');( C ) jest dobrym cross-browser szybkie rozwiązanie dla wszystkich ciągów.
  • Rozwiązania oparte na split-join( A, B ) lub replace( C, D ) są szybkie
  • Rozwiązania oparte na while( E, F, G, H ) są powolne - zwykle ~ 4 razy wolniej dla małych strun i około ~ 3000 razy (!) Wolniej dla długich strun
  • Rozwiązania rekurencyjne ( RA, RB ) są wolne i nie działają w przypadku długich łańcuchów

Tworzę również własne rozwiązanie. Wygląda na to, że obecnie jest to najkrótszy, który wykonuje pytanie:

str.split`abc`.join``

Detale

Testy przeprowadzono na Chrome 79.0, Safari 13.0.4 i Firefox 71.0 (64-bitowy). Testy RAi RBwykorzystanie rekurencji. Wyniki

Wpisz opis zdjęcia tutaj

Krótki ciąg znaków - 55 znaków

Możesz uruchomić testy na swoim komputerze TUTAJ . Wyniki dla Chrome:

Wpisz opis zdjęcia tutaj

Długi ciąg: 275 000 znaków

Rozwiązania rekurencyjne RA i RB daje

RangeError: Przekroczono maksymalny rozmiar stosu wywołań

W przypadku 1 mln znaków łamią nawet Chrome

wprowadź opis zdjęcia tutaj

Próbuję przeprowadzić testy dla znaków 1M dla innych rozwiązań, ale E, F, G, H zajmuje tyle czasu, że przeglądarka prosi mnie o przerwanie skryptu, więc zmniejszam ciąg testowy do 275K znaków. Możesz uruchomić testy na swoim komputerze TUTAJ . Wyniki dla Chrome

wprowadź opis zdjęcia tutaj

Kod użyty w testach


1
To jest do cholery szczegółowa odpowiedź! Dziękuję Ci bardzo! Chociaż jestem ciekawy, dlaczego składnia „nowej RegExp (...)” daje taką poprawę.
— Márk Gergely Dolinka

21

Jeśli to, co chcesz znaleźć, znajduje się już w ciągu, a nie masz pod ręką escargera wyrażeń regularnych, możesz użyć funkcji join / split:

    function replaceMulti(haystack, needle, replacement)
    {
        return haystack.split(needle).join(replacement);
    }

    someString = 'the cat looks like a cat';
    console.log(replaceMulti(someString, 'cat', 'dog'));


dzięki! To rozwiązanie działa idealnie na mój problem :)
— xero399

19
function replaceAll(str, find, replace) {
  var i = str.indexOf(find);
  if (i > -1){
    str = str.replace(find, replace); 
    i = i + replace.length;
    var st2 = str.substring(i);
    if(st2.indexOf(find) > -1){
      str = str.substring(0,i) + replaceAll(st2, find, replace);
    }       
  }
  return str;
}

Zastanawiam się, jak dobrze to działa ... podciąg jest rodzimy lub przechodzi przez tablicę znaków, aby utworzyć nowe znaki.
— mmm

16

Podoba mi się ta metoda (wygląda trochę czystiej):

text = text.replace(new RegExp("cat","g"), "dog"); 

1
Okej, w jaki sposób unikasz ciągu znaków, aby użyć go jako wzorca wyrażenia regularnego?
— rakslice,

Nie, po prostu używam go jako zwykłego tekstu
— Owen

15

Najprostszym sposobem na to bez użycia wyrażenia regularnego jest podzielenie i dołączenie, tak jak kod tutaj:

var str = "Test abc test test abc test test test abc test test abc";
str.split('abc').join('')


13
while (str.indexOf('abc') !== -1)
{
    str = str.replace('abc', '');
}

13

Jeśli ciąg znaków zawiera podobny wzór abccc, możesz użyć tego:

str.replace(/abc(\s|$)/g, "")

13

Poprzednie odpowiedzi są zbyt skomplikowane. Wystarczy użyć funkcji zamiany w ten sposób:

str.replace(/your_regex_pattern/g, replacement_string);

Przykład:

var str = "Test abc test test abc test test test abc test test abc";

var res = str.replace(/[abc]+/g, "");

console.log(res);


10

Jeśli próbujesz upewnić się, że szukany ciąg nie będzie istniał nawet po zamianie, musisz użyć pętli.

Na przykład:

var str = 'test aabcbc';
str = str.replace(/abc/g, '');

Po zakończeniu nadal będziesz mieć „test abc”!

Najprostszą pętlą do rozwiązania tego byłoby:

var str = 'test aabcbc';
while (str != str.replace(/abc/g, '')){
   str.replace(/abc/g, '');
}

Ale to uruchamia wymianę dwa razy dla każdego cyklu. Być może (istnieje ryzyko odrzucenia) można to połączyć w celu uzyskania nieco bardziej wydajnej, ale mniej czytelnej formy:

var str = 'test aabcbc';
while (str != (str = str.replace(/abc/g, ''))){}
// alert(str); alerts 'test '!

Może to być szczególnie przydatne, gdy szukasz duplikatów ciągów.
Na przykład, jeśli mamy „a ,,, b” i chcemy usunąć wszystkie zduplikowane przecinki.
[W takim przypadku można zrobić .replace (/, + / g, ','), ale w pewnym momencie regex staje się wystarczająco złożony i powolny, aby zamiast tego zapętlić.]


10

Chociaż ludzie wspominali o użyciu wyrażenia regularnego, ale istnieje lepsze podejście, jeśli chcesz zastąpić tekst bez względu na wielkość liter. Jak wielkie lub małe litery. Użyj poniższej składni

//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');

//Output will be all the occurrences removed irrespective of casing.

Szczegółowy przykład możesz znaleźć tutaj .


z przykładowej witryny: „/ toBeReplacedString / gi to regex, którego musisz użyć. Tutaj g oznacza dopasowanie globalne, a i oznacza
— wielkość

8

Możesz po prostu użyć poniższej metody

/**
 * Replace all the occerencess of $find by $replace in $originalString
 * @param  {originalString} input - Raw string.
 * @param  {find} input - Target key word or regex that need to be replaced.
 * @param  {replace} input - Replacement key word
 * @return {String}       Output string
 */
function replaceAll(originalString, find, replace) {
  return originalString.replace(new RegExp(find, 'g'), replace);
};

7

Poprostu dodaj /g

document.body.innerHTML = document.body.innerHTML.replace('hello', 'hi');

do

// Replace 'hello' string with /hello/g regular expression.
document.body.innerHTML = document.body.innerHTML.replace(/hello/g, 'hi');

/g oznacza globalny

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.