Ich brauchte eine Lösung, bei der die zu ersetzenden Zeichenfolgen reguläre Ausdrücke sein können, zum Beispiel, um einen langen Text zu normalisieren, indem mehrere Leerzeichen durch ein einziges ersetzt werden. Aufbauend auf einer Kette von Antworten von anderen, einschließlich MiniQuark und mmj, habe ich folgendes gefunden:
def multiple_replace(string, reps, re_flags = 0):
""" Transforms string, replacing keys from re_str_dict with values.
reps: dictionary, or list of key-value pairs (to enforce ordering;
earlier items have higher priority).
Keys are used as regular expressions.
re_flags: interpretation of regular expressions, such as re.DOTALL
"""
if isinstance(reps, dict):
reps = reps.items()
pattern = re.compile("|".join("(?P<_%d>%s)" % (i, re_str[0])
for i, re_str in enumerate(reps)),
re_flags)
return pattern.sub(lambda x: reps[int(x.lastgroup[1:])][1], string)
Es funktioniert zum Beispiel für die in anderen Antworten genannten Beispiele:
>>> multiple_replace("(condition1) and --condition2--",
... {"condition1": "", "condition2": "text"})
'() and --text--'
>>> multiple_replace('hello, world', {'hello' : 'goodbye', 'world' : 'earth'})
'goodbye, earth'
>>> multiple_replace("Do you like cafe? No, I prefer tea.",
... {'cafe': 'tea', 'tea': 'cafe', 'like': 'prefer'})
'Do you prefer tea? No, I prefer cafe.'
Das Wichtigste für mich ist, dass man auch reguläre Ausdrücke verwenden kann, z. B. um nur ganze Wörter zu ersetzen oder um Leerzeichen zu normalisieren:
>>> s = "I don't want to change this name:\n Philip II of Spain"
>>> re_str_dict = {r'\bI\b': 'You', r'[\n\t ]+': ' '}
>>> multiple_replace(s, re_str_dict)
"You don't want to change this name: Philip II of Spain"
Wenn Sie die Wörterbuchschlüssel als normale Zeichenketten verwenden wollen, können Sie diese vor dem Aufruf von multiple_replace z. B. mit dieser Funktion entschlüsseln:
def escape_keys(d):
""" transform dictionary d by applying re.escape to the keys """
return dict((re.escape(k), v) for k, v in d.items())
>>> multiple_replace(s, escape_keys(re_str_dict))
"I don't want to change this name:\n Philip II of Spain"
Die folgende Funktion kann dabei helfen, fehlerhafte reguläre Ausdrücke in Ihren Wörterbuchschlüsseln zu finden (da die Fehlermeldung von multiple_replace nicht sehr aussagekräftig ist):
def check_re_list(re_list):
""" Checks if each regular expression in list is well-formed. """
for i, e in enumerate(re_list):
try:
re.compile(e)
except (TypeError, re.error):
print("Invalid regular expression string "
"at position {}: '{}'".format(i, e))
>>> check_re_list(re_str_dict.keys())
Beachten Sie, dass die Ersetzungen nicht verkettet, sondern gleichzeitig durchgeführt werden. Das macht sie effizienter, ohne ihre Möglichkeiten einzuschränken. Um den Effekt der Verkettung zu imitieren, müssen Sie vielleicht nur mehr Paare von Zeichenfolgen-Ersetzungen hinzufügen und die erwartete Reihenfolge der Paare sicherstellen:
>>> multiple_replace("button", {"but": "mut", "mutton": "lamb"})
'mutton'
>>> multiple_replace("button", [("button", "lamb"),
... ("but", "mut"), ("mutton", "lamb")])
'lamb'
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.