Problem mit Umlauten - ü ist nicht gleich ü

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Christian24
User
Beiträge: 2
Registriert: Sonntag 17. August 2014, 10:51

Hallo,

ich habe hier ein Problem mit dem Ersatz von Umlauten in Strings.

Code: Alles auswählen

translation_table = {
    "Ä": "Ae",
    "ä": "ae",
    "Ö": 'Oe',
    "ö": "oe",
    "Ü": "Ue",
    "ü": "ue",
    "ß": "ss"
} 

# 1.) String ist das Ergebnis eines dir auf den Verzeichnisbaum
# ... Ergebnis in eine Liste
# ... String ist ein Eintrag aus dem String
print("/Volumes/tmpEMPs/gefüllteBoxNegativ.emp".translate(str.maketrans(translation_table)))
# Ausgabe mit Umlaut ü

# 2.)
print("/Volumes/tmpEMPs/gefüllteBoxNegativ.emp". translate(str.maketrans(translation_table)))
# Ausgabe mit Umlaut in ue geaendert
1.) Ich liste mittels Python ein Verzeichnis rekursiv und lasse die gefundenen Verzeichniseinträge in eine Liste schreiben.
Gebe ich diese Einträge mittels des beigefügten Codebeispieles aus, so habe ich immer noch meinen Umlaut "ü".
2.) Schreibe ich den gleichen Text, der mir unter 1.) per Script geliefert wurde in den Text per Hand, so wird der Umlaut "ü" sauber übersetzt.
3.) Kopiere ich den Umlaut "ü" aus dem unter 1.) genannten Ergebnisses eines Scriptes in die Übersetzungstabelle, so bekomme ich folgende Fehlermeldung:

Code: Alles auswählen

...
print("/Volumes/tmpEMPs/gefüllteBoxNegativ.emp".translate(str.maketrans(translation_table)))
ValueError: string keys in translate table must be of length 1
Ich vermute, ich bin hier in einen Fettnapf zum Thema Zeichencodierung getreten, ab so richtig komme ich hier nicht weiter.

System MacOsX und das gelistete Volume liegt auf einem NAS mit einem Linux drauf.

Wer kann helfen?

Gruß,

Christian.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Welches Problem möchtest du denn genau lösen? Das Ersetzen von Umlauten in Dateipfaden hört sich zunächst nicht so an, als ob man das unbedingt tun möchte. Vielleicht gibt es eine bessere Lösung für dein echtes Problem.
Das Leben ist wie ein Tennisball.
Christian24
User
Beiträge: 2
Registriert: Sonntag 17. August 2014, 10:51

Hallo,

doch, genau das möchte ich machen!
... und natuerlich verstehen, was hier nicht wie gedacht funktioniert!

Gruss,

Christian.
BlackJack

@Christian24: Bei Dateisystemen under MacOS muss man sich dann auch mal mit Normalisierungen bei Unicode beschäftigen. Umlaute (und auch andere Zeichen) kann man in Unicode nämlich auf verschiedene Arten darstellen, einmal als ”precomposed” Zeichen, also *ein* Codepoint der zum Beispiel ein 'ü' repräsentiert, oder als zwei Codepoints, einer der ein 'u' repräsentiert und dann einer der die ”Umlautpunkte” repräsentiert.

Code: Alles auswählen

In [13]: print a, b
ü ü

In [14]: a
Out[14]: u'\xfc'

In [15]: b
Out[15]: u'u\u0308'

In [16]: unicodedata.name(a)
Out[16]: 'LATIN SMALL LETTER U WITH DIAERESIS'

In [17]: unicodedata.name(b[1])
Out[17]: 'COMBINING DIAERESIS'

In [18]: a == b
Out[18]: False
Im `unicodedata`-Modul sind Normalisierungsfunktionen.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hier eventuell noch der zugehörige Unicode-Artikel: http://www.unicode.org/reports/tr15/tr15-41.html

Sollte man wahrscheinlich ein mal lesen (Müsste ich auch mal machen).


Aus Interesse: Müsste ich dann bei jedem Vergleich, falls ich das Programm auch unter Mac benutzen möchte, folgendes machen?

Code: Alles auswählen

wert1 == unicodedata.normalize("NFC", wert2)
machen? NFC trennt das Zeichen ja erst und baut es dann wieder zu einem Zeichen zusammen, so wie alle anderen Betriebssysteme das auch direkt schreiben, oder?

Ich sehe da aber eventuell das Problem, dass manche Zeichen ja trotz Normalisierung mehrere Codepunkte haben (wenn es kein fertiges Zeichen gibt), aber dann kann ich das ja gar nicht vergleichen, oder?
BlackJack

@Hellstorm: Den letzten Teil habe ich nicht verstanden. Wenn es kein precomposed Zeichen für etwas gibt, wieso sollte man es dann nicht vergleichen können?

Ansonsten musst Du streng genommen vor dem Vergleich *beide* Werte normalisieren. Ob man dafür dann NFC oder NFD nimmt, ist eigentlich egal. Also ``nfd(wert1) == nfd(wert2)`` mit ``nfd = functools.partial(unicodedata.normalize, 'NFD')``.
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

BlackJack hat geschrieben:@Hellstorm: Den letzten Teil habe ich nicht verstanden. Wenn es kein precomposed Zeichen für etwas gibt, wieso sollte man es dann nicht vergleichen können?
Hm, ich meinte das, falls man z.B. mit einer for-Schleife über eine Zeichenkette geht. Da wird doch jedes Zeichen einzeln „herausgetrennt“ (denke ich einfach mal). Aber was genau ist ein Zeichen für Python? Wenn man das Beispiel vom TE nimmt, wäre ein U+0061/U+0308-ä ja zwei Zeichen, wenn man dann mit for darübergeht, hätte man ja erst ein 0061 (a) + danach ein U+0308. Das könnte man dann ja nicht mehr normalisieren.

Code: Alles auswählen

In [23]: for char in "\u0061\u0308": print(ord(char))
97
776

Code: Alles auswählen

In [27]: for char in "\u0061\u0308": print(ord(unicodedata.normalize("NFC", char)))
97
776
Edit: Danke übrigens für functools.partial, wieder was gelernt.

Edit2: Ok, einfach unicodedata.normalize vorher über die gesamte Zeichenkette laufen lassen. Dann gehts.
Antworten