Chciałbym użyć funkcji .replace do zastąpienia wielu ciągów.
Obecnie mam
string.replace("condition1", "")
ale chciałbym mieć coś takiego
string.replace("condition1", "").replace("condition2", "text")
chociaż nie wydaje się to dobrą składnią
jaki jest właściwy sposób to zrobić? tak jak w grep / regex możesz zrobić \1
i \2
zamienić pola na określone ciągi wyszukiwania
Odpowiedzi:
Oto krótki przykład, który powinien załatwić sprawę z wyrażeniami regularnymi:
Na przykład:
źródło
"spamham sha".replace("spam", "eggs").replace("sha","md5")
bycie"eggmd5m md5"
zamiast"eggsham md5"
Możesz po prostu zrobić przyjemną małą funkcję zapętlania.
gdzie
text
jest kompletnym ciągiem idic
słownikiem - każda definicja jest ciągiem, który zastąpi dopasowanie do terminu.Uwaga : w Pythonie 3
iteritems()
został zastąpiony przezitems()
Ostrożnie: słowniki Pythona nie mają niezawodnej kolejności iteracji. To rozwiązanie rozwiązuje problem tylko wtedy, gdy:
Na przykład:
Możliwe wyjście nr 1:
Możliwe wyjście # 2
Jedną z możliwych poprawek jest użycie polecenia OragedDict.
Wynik:
Ostrożnie # 2: Niewystarczające, jeśli
text
łańcuch jest zbyt duży lub w słowniku jest wiele par.źródło
OrderedDict
- lub listy 2-krotek.Dlaczego nie jedno takie rozwiązanie?
źródło
Oto wariant pierwszego rozwiązania wykorzystującego redukcję, na wypadek gdybyś chciał być funkcjonalny. :)
jeszcze lepsza wersja martineau:
źródło
repls
sekwencję krotek i zrezygnować ziteritems()
połączenia. tj .repls = ('hello', 'goodbye'), ('world', 'earth')
ireduce(lambda a, kv: a.replace(*kv), repls, s)
.reduce
został usunięty .reduce
nadal istnieje, jednak stał się częściąfunctools
modułu (patrz dokumentacja ) w Pythonie 3, więc kiedy powiedziałem bez zmian, miałem na myśli, że można uruchomić ten sam kod - choć trzeba byreduce
było,import
gdyby był konieczny ponieważ nie jest już wbudowany.To tylko bardziej zwięzłe podsumowanie świetnych odpowiedzi FJ i MiniQuark. Wszystko, czego potrzebujesz, aby uzyskać jednoczesne zastępowanie ciągów, to następująca funkcja:
Stosowanie:
Jeśli chcesz, możesz stworzyć własne dedykowane funkcje zastępcze, zaczynając od tej prostszej.
źródło
rep_dict = {"but": "mut", "mutton": "lamb"}
że ciąg znaków"button"
kończy się na"mutton"
twoim kodzie, ale dałby,"lamb"
gdyby zamienniki były powiązane łańcuchem, jeden po drugim.Do you prefer cafe? No, I prefer cafe.
, co wcale nie jest pożądane.Zbudowałem to na doskonałej odpowiedzi FJ:
Użycie jednego strzału:
Zauważ, że ponieważ wymiana odbywa się w jednym przejściu, „kawiarnia” zmienia się w „herbata”, ale nie zmienia się z powrotem w „kawiarnia”.
Jeśli musisz wykonać tę samą wymianę wiele razy, możesz łatwo utworzyć funkcję zamiany:
Ulepszenia:
Cieszyć się! :-)
źródło
pattern.sub
oczekuje funkcji z tylko jednym parametrem (tekst do zastąpienia), więc funkcja musi mieć dostęp doreplace_dict
.re.M
zezwala na zamiany Multiline (jest to dobrze wyjaśnione w dokumencie: docs.python.org/2/library/re.html#re.M ).Chciałbym zaproponować użycie szablonów ciągów. Wystarczy umieścić ciąg do zamiany w słowniku i wszystko jest ustawione! Przykład z docs.python.org
źródło
substitute
się wyjątek, więc zachowaj ostrożność podczas pobierania szablonów od użytkowników.W moim przypadku potrzebowałem prostej zamiany unikatowych kluczy na nazwy, więc wymyśliłem to:
źródło
i
gos
, otrzymasz dziwne zachowanie.b = [ ['i', 'Z'], ['s', 'Y'] ]; for x,y in (b): a = a.replace(x, y)
Jeśli więc ostrożnie zamawiasz pary tablic, możesz upewnić się, że nie zastąpisz () rekurencyjnie.Zaczynając
Python 3.8
i wprowadzając wyrażenia przypisania (PEP 572) (:=
operator), możemy zastosować zamiany w ramach zrozumienia listy:źródło
['The quick red fox jumps over the lazy dog', 'The quick red fox jumps over the quick dog']
. Ale wyrażenie przypisania (text := text.replace
) również iteracyjnie buduje nowe wersjetext
, mutując je. Po zapoznaniu się z listą możesz użyćtext
zmiennej zawierającej zmodyfikowany tekst.text
jako jednowierszową, możesz także użyć[text := text.replace(a, b) for a, b in replacements][-1]
(zwróć uwagę na[-1]
), który wyodrębnia ostatni element zrozumienia listy; tj. ostatnia wersjatext
.Oto moje 0,02 $. Opiera się na odpowiedzi Andrew Clarka, nieco jaśniej, i obejmuje również przypadek, gdy ciąg do zastąpienia jest podciągiem innego ciągu do zastąpienia (dłuższy ciąg wygrywa)
To właśnie w tym tego GIST , nie krępuj się go zmodyfikować, jeśli masz jakieś propozycję.
źródło
Potrzebowałem rozwiązania, w którym ciągi do zamiany mogą być wyrażeniami regularnymi, na przykład, aby pomóc w normalizacji długiego tekstu przez zastąpienie wielu białych znaków jednym. Opierając się na szeregu odpowiedzi od innych, w tym MiniQuark i mmj, wymyśliłem:
Działa z przykładami podanymi w innych odpowiedziach, na przykład:
Najważniejsze dla mnie jest to, że możesz również używać wyrażeń regularnych, na przykład, aby zamieniać tylko całe słowa lub normalizować białe znaki:
Jeśli chcesz używać kluczy słownika jako normalnych ciągów znaków, możesz uciec przed nimi przed wywołaniem wielu_replace przy użyciu np. Tej funkcji:
Poniższa funkcja może pomóc w znalezieniu błędnych wyrażeń regularnych wśród kluczy słownika (ponieważ komunikat o błędzie z wielu_replace nie jest zbyt wymowny):
Pamiętaj, że nie łączy łańcuchów zamienników, zamiast tego wykonuje je jednocześnie. To sprawia, że jest bardziej wydajny bez ograniczania tego, co może zrobić. Aby naśladować efekt łączenia, konieczne może być dodanie większej liczby par zamieniających łańcuchy i zapewnienie oczekiwanego uporządkowania par:
źródło
Oto próbka, która jest bardziej wydajna na długich ciągach z wieloma małymi zamiennikami.
Chodzi o to, by uniknąć wielu połączeń długich łańcuchów. Przecinamy łańcuch źródłowy na fragmenty, zastępując niektóre fragmenty podczas tworzenia listy, a następnie łączymy całość z powrotem w łańcuch.
źródło
Naprawdę nie powinieneś tego robić w ten sposób, ale uważam to za zbyt fajne:
Teraz
answer
jest wynikiem wszystkich zamian po koleiznowu, jest to bardzo zuchwałe i nie jest czymś, z czego powinieneś regularnie korzystać. Ale miło jest wiedzieć, że możesz zrobić coś takiego, jeśli zajdzie taka potrzeba.
źródło
Walczyłem również z tym problemem. Przy wielu podstawieniach wyrażenia regularne zmagają się i są około czterokrotnie wolniejsze niż zapętlenie
string.replace
(w warunkach mojego eksperymentu).Powinieneś bezwzględnie spróbować użyć biblioteki Flashtext ( post na blogu tutaj , Github tutaj ). W moim przypadku było to nieco ponad dwa rzędy wielkości szybciej, od 1,8 s do 0,015 s (wyrażenia regularne trwały 7,7 s) dla każdego dokumentu.
Łatwo jest znaleźć przykłady użycia w powyższych linkach, ale jest to działający przykład:
Zauważ, że Flashtext dokonuje podstawień w jednym przebiegu (aby uniknąć a -> b i b -> c tłumaczenia „a” na „c”). Flashtext szuka również całych słów (więc „is” nie pasuje do „th is ”). Działa dobrze, jeśli twój cel składa się z kilku słów (zamieniając „To jest” na „Cześć”).
źródło
<p>
z/n
. Próbowałem twojego podejścia, ale z tagami flashtext nie wydaje się go analizować?<
i>
oznaczyć koniec słowa (ale zostać uwzględnionym w zastępowaniu)?Wydaje mi się, że to pytanie wymaga jednokreskowej rekurencyjnej odpowiedzi na funkcję lambda dla kompletności, tylko dlatego. Więc tam:
Stosowanie:
Uwagi:
Uwaga: Podobnie jak w przypadku wszystkich funkcji rekurencyjnych w pythonie, zbyt duża głębokość rekurencji (tj. Zbyt duże słowniki zastępcze) spowoduje błąd. Zobacz np . Tutaj .
źródło
sys.getrecursionlimit()
to kilka 1000, maks. użyj pętli lub czegoś podobnego lub spróbuj uprościć podstawienia.Nie wiem o prędkości, ale to moja szybka poprawka w dniu pracy:
... ale podoba mi się odpowiedź nr 1 powyżej. Uwaga - jeśli jedna nowa wartość jest podciągiem innej, wówczas operacja nie jest przemienna.
źródło
Możesz użyć
pandas
biblioteki ireplace
funkcji, która obsługuje zarówno dokładne dopasowania, jak i zamiany wyrażeń regularnych. Na przykład:Zmodyfikowany tekst to:
Można znaleźć przykład tutaj . Zauważ, że zamiany tekstu są wykonywane w kolejności, w jakiej pojawiają się na listach
źródło
Aby zastąpić tylko jeden znak, użyj
translate
istr.maketrans
jest moją ulubioną metodą.tl; dr>
result_string = your_string.translate(str.maketrans(dict_mapping))
próbny
źródło
Począwszy od cennej odpowiedzi Andrew, opracowałem skrypt, który ładuje słownik z pliku i opracowuje wszystkie pliki w otwartym folderze w celu wykonania zamiany. Skrypt ładuje mapowania z zewnętrznego pliku, w którym można ustawić separator. Jestem początkującym, ale uważam, że ten skrypt jest bardzo przydatny podczas wielokrotnego zastępowania w wielu plikach. Załadował słownik z ponad 1000 pozycji w ciągu kilku sekund. To nie jest eleganckie, ale działało dla mnie
źródło
to jest moje rozwiązanie problemu. Użyłem go w chatbocie, aby zastąpić różne słowa naraz.
to się stanie
The cat hunts the dog
źródło
Kolejny przykład: lista wprowadzania
Pożądane wyjście byłoby
Kod :
źródło
Lub po prostu szybki hack:
źródło
Oto inny sposób zrobienia tego za pomocą słownika:
źródło