Einmal translate() statt mehrmals replace()

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
snafu
User
Beiträge: 5633
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 24. November 2018, 10:10

Habe mich mal intensiver mit str.translate() beschäftigt. Im Forum sehe ich dessen Nutzung recht selten, eigentlich fällt mir gerade gar kein Fall ein. Daher verliere ich nun ein paar Worte dazu.

Häufig hat man ja das Problem, dass mehrere Ersetzungen in Texten gemacht werden müssen. Da replace() immer nur eine Art von Ersetzung vornehmen kann (alle X durch Y), behilft man sich mit einer Aneinanderreihung von replace()-Aufrufen. Sagen wir mal, es sollen alle "X", "Y" und "Z" gelöscht werden. Das sähe mit replace() dann so aus:

Code: Alles auswählen

text = 'fhgfdhgXghsgkhXYsgskgZZZhsfgfgYYshfsZXZkfghXYZfhg'
clean_text = text.replace('X', '').replace('Y', '').replace('Z', '')
Unschön zu schreiben und auch mit ungünstiger Laufzeit, da jeder replace()-Aufruf wieder den kompletten Text durchlaufen muss.

Hier kommt nun translate() ins Spiel: Es nimmt für die Übersetzung ein Mapping (z.B. Wörterbuch). Wichtig ist, dass die Schlüssel Ordinals sein müssen, also der "Zahlwert" eines Zeichens. Die Werte können ebenfalls Ordinals sein oder normaler Text (wie bei replace()) oder None, wenn das Zeichen gelöscht werden soll. Hier also obiges Beispiel mit translate():

Code: Alles auswählen

text = 'fhgfdhgXghsgkhXYsgskgZZZhsfgfgYYshfsZXZkfghXYZfhg'
table = dict.fromkeys(map(ord, 'XYZ'))
clean_text = text.translate(table)
translate() geht hierbei in einem Rutsch die infrage kommenden Ersetzungen durch. Ein mehrfaches Durchlaufen des Textes wird also vermieden.

Zugegeben, der Aufbau der Übersetzungstabelle wirkt etwas lowlevel, aber das lässt sich natürlich in eine Funktion auslagern, wenn man möchte.
shcol (Repo | Doc | PyPi)
Benutzeravatar
ThomasL
User
Beiträge: 419
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Samstag 24. November 2018, 10:31

Gut zu wissen, Danke.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
Benutzeravatar
snafu
User
Beiträge: 5633
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 24. November 2018, 10:43

Und wenn einem das mit dem Ordinals mappen zu nervig ist, dann kann man auch zu maketrans() greifen. Obige Übersetzungstabelle erhält man so:

Code: Alles auswählen

table = str.maketrans(dict.fromkeys('XYZ'))
Sicherlich möchte man nicht nur Zeichen löschen, sondern auch ersetzen. Hier finde ich maketrans() auf jeden Fall einfacher in der Handhabung. Ein Beispiel:

Code: Alles auswählen

text = 'gsgfgsShhgrgrSgrhgHsgrghrHsgrshkkEkkbbSuubklkbHkbuu'
table = str.maketrans({'S': 'Spam', 'H': 'Ham', 'E': 'Eggs'})
spammed_text = text.translate(table)
shcol (Repo | Doc | PyPi)
Antworten