Der einfachste Weg, eine Zeichenfolge mithilfe eines Wörterbuchs mit Ersetzungen zu ersetzen?


74

Erwägen..

dict = {
'Спорт':'Досуг',
'russianA':'englishA'
}

s = 'Спорт russianA'

Ich möchte alle Diktatschlüssel durch ihre jeweiligen Diktatwerte in ersetzen s.


1
Dies ist möglicherweise nicht so einfach. Sie sollten wahrscheinlich einen expliziten Tokenizer haben (zum Beispiel {'cat': 'russiancat'}und "Raupe"). Auch überlappende Wörter ( {'car':'russiancar', 'pet' : 'russianpet'}und "Teppich").
— Joe


2
Nebenbei: Ich denke, es dictwird am besten als Variablenname vermieden, da eine Variable dieses Namens die integrierte Funktion mit demselben Namen beschatten würde.
— Jochen

Antworten:


98

Verwenden von re:

import re

s = 'Спорт not russianA'
d = {
'Спорт':'Досуг',
'russianA':'englishA'
}

pattern = re.compile(r'\b(' + '|'.join(d.keys()) + r')\b')
result = pattern.sub(lambda x: d[x.group()], s)
# Output: 'Досуг not englishA'

Dies entspricht nur ganzen Wörtern. Wenn Sie das nicht brauchen, verwenden Sie das Muster:

pattern = re.compile('|'.join(d.keys()))

Beachten Sie, dass Sie in diesem Fall die absteigenden Wörter nach Länge sortieren sollten, wenn einige Ihrer Wörterbucheinträge Teilzeichenfolgen anderer sind.


24
Falls die Wörterbuchschlüssel Zeichen wie "^", "$" und "/" enthalten, müssen die Schlüssel maskiert werden, bevor der reguläre Ausdruck zusammengestellt wird. Zu diesem Zweck .join(d.keys())könnte durch ersetzt werden .join(re.escape(key) for key in d.keys()).
— Jochen

Bitte beachten Sie, dass das erste Beispiel (englосуг nicht englishA) nur in Python3 funktioniert. In Python2 gibt es mir immer noch "Спорт not englishA"
— Fruit

Es scheint zu scheitern, wenn das Wort im Diktat einen Punkt hat - https://regex101.com/r/bliVUS/1- Ich muss es \bam Ende entfernen, bin mir aber nicht sicher, ob es korrekt ist.
— Peter.k

24

Sie können die Reduktionsfunktion verwenden:

reduce(lambda x, y: x.replace(y, dict[y]), dict, s)

16
Anders als bei der Lösung von @Max Shawabkeh werden reducebei der Verwendung die Substitutionen nacheinander angewendet . Infolgedessen { 'red': 'green', 'green': 'red'}funktioniert das Austauschen von Wörtern mithilfe von Wörterbüchern nicht mit dem reducebasierenden Ansatz, und überlappende Übereinstimmungen werden auf unvorhersehbare Weise transformiert.
— Jochen

2
Ein gutes Beispiel dafür, warum wiederholte .replace()Anrufe unbeabsichtigte Folgen haben können: - html.replace('"', '"').replace('&', '&')Versuchen Sie es weiter html = '"foo"'.
— Zigg

Dies ist unnötig komplex und unlesbar im Vergleich zu der entfalteten Schleife, wie in den Antworten von ChristopheD oder user2769207 gezeigt .
— Poke

17

Hier gefundene Lösung (ich mag die Einfachheit):

def multipleReplace(text, wordDict):
    for key in wordDict:
        text = text.replace(key, wordDict[key])
    return text

11
Wie @jochen beschrieben hat, riskiert dies wiederum eine schlechte Übersetzung, wenn es einen Schlüssel gibt, der auch ein Wert ist. Ein Single-Pass-Ersatz wäre am besten.
— Chris

5

ein Weg, ohne re

d = {
'Спорт':'Досуг',
'russianA':'englishA'
}

s = 'Спорт russianA'.split()
for n,i in enumerate(s):
    if i in d:
        s[n]=d[i]
print ' '.join(s)

3
Dies wird fehlschlagen, wenn das Diktat Platz in seinen Schlüsseln hat
— Trinh Hoang Nhu

3

Fast das gleiche wie Ghostdog74, obwohl unabhängig erstellt. Ein Unterschied besteht darin, dass die Verwendung von d.get () anstelle von d [] Elemente verarbeiten kann, die nicht im Diktat enthalten sind.

>>> d = {'a':'b', 'c':'d'}
>>> s = "a c x"
>>> foo = s.split()
>>> ret = []
>>> for item in foo:
...   ret.append(d.get(item,item)) # Try to get from dict, otherwise keep value
... 
>>> " ".join(ret)
'b d x'

1

Ich habe dies in einer ähnlichen Situation verwendet (meine Zeichenfolge war alle in Großbuchstaben):

def translate(string, wdict):
    for key in wdict:
        string = string.replace(key, wdict[key].lower())
    return string.upper()

hoffe das hilft irgendwie ... :)


2
Es ist der Lösung von ChristopheD sehr ähnlich. Stimmen Sie ihm nicht zu?
— Hynekcer

1

Mit der Warnung, dass es fehlschlägt, wenn der Schlüssel über Speicherplatz verfügt, handelt es sich um eine komprimierte Lösung, die der Antwort von ghostdog74 und extaneons ähnelt:

d = {
'Спорт':'Досуг',
'russianA':'englishA'
}

s = 'Спорт russianA'

' '.join(d.get(i,i) for i in s.split())
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.