472 Stimmen

Wie kann man mehrere Teilstrings einer Zeichenkette ersetzen?

Ich möchte die Funktion .replace verwenden, um mehrere Zeichenfolgen zu ersetzen.

Ich habe derzeit

string.replace("condition1", "")

aber ich würde gerne etwas haben wie

string.replace("condition1", "").replace("condition2", "text")

obwohl sich das nicht nach einer guten Syntax anfühlt

Was ist der richtige Weg, um dies zu tun? ähnlich wie in grep/regex können Sie tun \1 y \2 um Felder durch bestimmte Suchbegriffe zu ersetzen

2 Stimmen

Ich habe mir die Zeit genommen, alle Antworten in verschiedenen Szenarien zu testen. Siehe stackoverflow.com/questions/59072514/

4 Stimmen

Die kurze Antwort lautet: Es gibt keinen besseren Weg, dies zu tun.

381voto

Andrew Clark Punkte 193562

Hier ist ein kurzes Beispiel, das den Trick mit regulären Ausdrücken machen sollte:

import re

rep = {"condition1": "", "condition2": "text"} # define desired replacements here

# use these three lines to do the replacement
rep = dict((re.escape(k), v) for k, v in rep.iteritems()) 
#Python 3 renamed dict.iteritems to dict.items so use rep.items() for latest versions
pattern = re.compile("|".join(rep.keys()))
text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text)

Zum Beispiel:

>>> pattern.sub(lambda m: rep[re.escape(m.group(0))], "(condition1) and --condition2--")
'() and --text--'

14 Stimmen

Der Austausch erfolgt in einem einzigen Durchgang.

21 Stimmen

Hallo, ich habe eine kleine Gist mit einer klareren Version dieses Snippets erstellt. Es sollte auch etwas effizienter sein: gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729

1 Stimmen

Nach einigen Benchmarking auf mit ersetzen mehrere Male vs Regex-Ersetzung auf eine Zeichenfolge mit zunehmender Länge durch Potenz von 2 mit 100 Ersetzungen hinzugefügt, scheint es, dass auf meinem Computer diese Methode ist die langsamste, wenn die Länge der Zeichenfolge ist weniger als 500 Zeichen, und die schnellste sonst. Für mein spezielles Problem habe ich eine dritte Methode, da alle Ersetzungen das gleiche Präfix haben, von dem ich weiß, dass es nirgendwo sonst in der Zeichenfolge vorkommt. Eine while-Schleife mit find+replace ist schneller als regex bei einer Länge von weniger als 20 000 Zeichen, aber langsamer als replace bei einer Länge von weniger als 500.

196voto

Joe Hansen Punkte 11608

Sie könnten einfach eine nette kleine Schleifenfunktion erstellen.

def replace_all(text, dic):
    for i, j in dic.iteritems():
        text = text.replace(i, j)
    return text

text ist die vollständige Zeichenkette und dic ist ein Wörterbuch - jede Definition ist eine Zeichenkette, die eine Übereinstimmung mit dem Begriff ersetzen wird.

Hinweis : in Python 3, iteritems() wurde ersetzt durch items()


Vorsichtig: Python-Wörterbücher haben keine zuverlässige Reihenfolge für die Iteration. Diese Lösung löst Ihr Problem nur, wenn:

  • die Reihenfolge der Ersetzungen ist unerheblich
  • es in Ordnung ist, wenn eine Ersetzung die Ergebnisse früherer Ersetzungen verändert

Aktualisierung: Die obige Aussage bezüglich der Reihenfolge der Einfügung gilt nicht für Python-Versionen größer oder gleich 3.6, da Standard-Dicts geändert wurden, um die Reihenfolge der Einfügung für die Iteration zu verwenden.

Zum Beispiel:

d = { "cat": "dog", "dog": "pig"}
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, d)
print(my_sentence)

Möglicher Ausgang #1:

"This is my pig and this is my pig."

Möglicher Ausgang #2

"This is my dog and this is my pig."

Eine mögliche Lösung ist die Verwendung eines OrderedDict.

from collections import OrderedDict
def replace_all(text, dic):
    for i, j in dic.items():
        text = text.replace(i, j)
    return text
od = OrderedDict([("cat", "dog"), ("dog", "pig")])
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, od)
print(my_sentence)

Sortie :

"This is my pig and this is my pig."

Vorsicht #2: Ineffizient, wenn Ihr text String zu groß ist oder viele Paare im Wörterbuch vorhanden sind.

9 Stimmen

Von der Leistung her ist es schlimmer als das, was Valentin sagt - es wird den Text so oft durchlaufen, wie es Elemente in dic! gibt. Gut, wenn "Text" ist klein, aber schrecklich für großen Text.

183voto

Enrico Bianchi Punkte 1792

Warum nicht eine Lösung wie diese?

s = "The quick brown fox jumps over the lazy dog"
for r in (("brown", "red"), ("lazy", "quick")):
    s = s.replace(*r)

#output will be:  The quick red fox jumps over the quick dog

8 Stimmen

Dies leidet unter dem Ordnungsproblem einer mehrfachen replace Ansatz, "abc" und Ihre Ersatzleute sind (("a", "b"), ("b", "a")) Sie könnten erwarten "bac" aber Sie bekommen "aac" . Hinzu kommt das Leistungsproblem, dass bei jedem Aufruf die gesamte Zeichenkette gescannt werden muss, so dass die Komplexität mindestens O(number of replacements * len(s)) plus den String-Musterabgleich, der unter der Haube stattfindet.

120voto

Björn Lindqvist Punkte 17705

Hier ist eine Variante der ersten Lösung mit reduce, falls Sie gerne funktional sind :)

repls = {'hello' : 'goodbye', 'world' : 'earth'}
s = 'hello, world'
reduce(lambda a, kv: a.replace(*kv), repls.iteritems(), s)

die noch bessere Version von Martineau:

repls = ('hello', 'goodbye'), ('world', 'earth')
s = 'hello, world'
reduce(lambda a, kv: a.replace(*kv), repls, s)

60voto

mmj Punkte 5051

Dies ist nur eine kürzere Zusammenfassung der großartigen Antworten von F.J und MiniQuark und der letzten, aber entscheidenden Verbesserung von bgusach. Alles, was Sie brauchen, um zu erreichen mehrere gleichzeitige Ersetzungen von Zeichenfolgen ist die folgende Funktion:

def multiple_replace(string, rep_dict):
    pattern = re.compile("|".join([re.escape(k) for k in sorted(rep_dict,key=len,reverse=True)]), flags=re.DOTALL)
    return pattern.sub(lambda x: rep_dict[x.group(0)], string)

Uso:

>>>multiple_replace("Do you like cafe? No, I prefer tea.", {'cafe':'tea', 'tea':'cafe', 'like':'prefer'})
'Do you prefer tea? No, I prefer cafe.'

Wenn Sie möchten, können Sie ausgehend von dieser einfacheren Funktion Ihre eigenen Ersatzfunktionen entwickeln.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X