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 abc
powyższego ciągu.
Jak mogę zastąpić wszystkie jego wystąpienia?
javascript
string
replace
Kliknij opcję Upvote
źródło
źródło
aba
wababa
zca
, skutkujących można się spodziewać?caba
?abca
?cca
?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.replaceAll
zastę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.replaceAll
zgłasza wyjątek ”Odpowiedzi:
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ć
Ogólny wzór to
W niektórych przypadkach było to szybsze niż używanie
replaceAll
i 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.
źródło
String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}
. Użycie:"My string".replaceAll('st', '');
tworzy „Mój pierścień”replaceAll
funkcję, a stanie się on tak samo czytelny jak wszystko inne. Ponieważ wydajność nie jest zła, nie ma powodu, aby unikać tego rozwiązania.W odpowiedzi na komentarz:
W odpowiedzi na komentarz Click Upvote możesz uprościć go jeszcze bardziej:
Uwaga: Wyrażenia regularne zawierają znaki specjalne (meta) i dlatego niebezpieczne jest ślepe przekazywanie argumentu w
find
powyż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):Aby więc uczynić
replaceAll()
powyższą funkcję bezpieczniejszą, można ją zmodyfikować w następujący sposóbescapeRegExp
:źródło
function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; }
replaceAll
implementacji jest to, że nie będzie działać, jeślifind
zawiera metaznaki.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
String
wbudowanego prototypu.Implementacja oparta na wyrażeniach regularnych
Implementacja Split and Join (funkcjonalna)
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
search
zawiera 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:Moglibyśmy wywoływać
escapeRegExp
w ramach naszejString.prototype.replaceAll
implementacji, 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).źródło
Użycie wyrażenia regularnego z
g
ustawioną flagą zastąpi wszystkie:Zobacz także tutaj
źródło
var sourceText
liczenie liczby wystąpień (numOfInstances
) za pomocąsubstring
lub podzielić i policzyć długość (między innymi strategiami)thatWhichYouWantToReplace
następnie wykonajfor (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/g
jest tak łatwe i prawdopodobnie bardziej wydajne.Oto funkcja prototypu łańcucha w oparciu o przyjętą odpowiedź:
EDYTOWAĆ
Jeśli twoja
find
wola zawiera znaki specjalne, musisz uciec przed nimi:Fiddle: http://jsfiddle.net/cdbzL/
źródło
find
zawiera znaki podobne.
lub$
mające specjalne znaczenie w wyrażeniu regularnym?var str = this
tworzy drugie odwołanie do niezmiennego łańcucha, do któregoreplace
stosowana 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');
isomeStrVar
został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;
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
)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 jakcool-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!
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:
Dane wyjściowe są takie same, jak zaakceptowana odpowiedź, przy użyciu wyrażenia / cat / g na tym ciągu:
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:
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
.replace
uż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 jednocat
i drugiecats
za jednym razem:źródło
Dopasuj do globalnego wyrażenia regularnego:
źródło
Aby zastąpić jednorazowe użycie:
Aby wymienić wiele razy, użyj:
źródło
replace(/\n/g, '<br/>')
Są to najbardziej popularne i czytelne metody.
Metoda 1:
Metoda 2:
Metoda 3:
Metoda 4:
Wynik:
źródło
Lub wypróbuj tutaj funkcję replaceAll:
Jakie są użyteczne metody JavaScript, które rozszerzają wbudowane obiekty?
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
źródło
Korzystanie
RegExp
z JavaScript może zrobić to za Ciebie, po prostu zrób coś takiego jak poniższy kod, nie zapomnij,/g
po czym wyróżnia się globalnie :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:
i po prostu używaj go w kodzie w kółko, jak poniżej:
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ć.
źródło
Powiedz, że chcesz zamienić wszystkie „abc” na „x”:
Próbowałem wymyślić coś prostszego niż modyfikacja prototypu łańcucha.
źródło
Użyj wyrażenia regularnego:
źródło
Zastępowanie pojedynczych cytatów:
źródło
// zapętlić go, aż liczba wystąpień osiągnie wartość 0. LUB po prostu skopiuj / wklej
źródło
.indexOf
w zmiennej i użyj tej zmiennej jako drugiego parametru.indexOf
(minus długość słowa kluczowego plus długość ciągu zastępującego).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 (""
).str
jest ł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ć.źródło
To jest najszybsza wersja, która nie używa wyrażeń regularnych .
Zmieniono jsperf
Jest prawie dwa razy szybszy niż metoda dzielenia i łączenia.
Jak wskazano w komentarzu tutaj, nie zadziała to, jeśli
omit
zmienna zawieraplace
, 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 )!
źródło
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ć}
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.split-join
( A, B ) lubreplace
( C, D ) są szybkiewhile
( E, F, G, H ) są powolne - zwykle ~ 4 razy wolniej dla małych strun i około ~ 3000 razy (!) Wolniej dla długich strunTworzę również własne rozwiązanie. Wygląda na to, że obecnie jest to najkrótszy, który wykonuje pytanie:
Pokaż fragment kodu
Detale
Testy przeprowadzono na Chrome 79.0, Safari 13.0.4 i Firefox 71.0 (64-bitowy). Testy
RA
iRB
wykorzystanie rekurencji. WynikiKrótki ciąg znaków - 55 znaków
Możesz uruchomić testy na swoim komputerze TUTAJ . Wyniki dla Chrome:
Długi ciąg: 275 000 znaków
Rozwiązania rekurencyjne RA i RB daje
W przypadku 1 mln znaków łamią nawet Chrome
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
Kod użyty w testach
Pokaż fragment kodu
źródło
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:
źródło
źródło
Podoba mi się ta metoda (wygląda trochę czystiej):
źródło
Najprostszym sposobem na to bez użycia wyrażenia regularnego jest podzielenie i dołączenie, tak jak kod tutaj:
źródło
http://jsfiddle.net/ANHR9/
źródło
źródło
Jeśli ciąg znaków zawiera podobny wzór
abccc
, możesz użyć tego:źródło
Poprzednie odpowiedzi są zbyt skomplikowane. Wystarczy użyć funkcji zamiany w ten sposób:
Przykład:
źródło
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:
Po zakończeniu nadal będziesz mieć „test abc”!
Najprostszą pętlą do rozwiązania tego byłoby:
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:
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ć.]
źródło
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
Szczegółowy przykład możesz znaleźć tutaj .
źródło
Możesz po prostu użyć poniższej metody
źródło
Poprostu dodaj
/g
do
/g
oznacza globalnyźródło