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.