Ich brauchte eine Lösung, bei der die zu ersetzenden Zeichenfolgen reguläre Ausdrücke sein können, um beispielsweise einen langen Text zu normalisieren, indem mehrere Leerzeichen durch ein einzelnes ersetzt werden. Aufbauend auf einer Reihe von Antworten anderer, einschließlich MiniQuark und mmj, habe ich mir Folgendes ausgedacht:
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 für die Beispiele in anderen Antworten, zum Beispiel:
>>> 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.'
Die Hauptsache für mich ist, dass Sie auch reguläre Ausdrücke verwenden können, um beispielsweise nur ganze Wörter zu ersetzen oder 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 Zeichenfolgen verwenden möchten, können Sie diese vor dem Aufruf von multiple_replace mit folgender Funktion umgehen:
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 ausgeführt werden. Dies macht es effizienter, ohne die Möglichkeiten einzuschränken. Um den Effekt der Verkettung nachzuahmen, müssen Sie möglicherweise nur weitere Zeichenfolgenersatzpaare 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'