Blog

Behandlung von Kodierungsproblemen mit Unicode-Normalisierung in Python

Aktualisiert Oktober 21, 2025
6 Minuten

Beim Lesen und Schreiben von verschiedenen Systemen kommt es nicht selten zu Kodierungsproblemen, wenn die Systeme unterschiedliche Gebietsschemata haben. In diesem Beitrag zeige ich Ihnen mehrere Optionen für den Umgang mit solchen Problemen.

Beispiel

Nehmen wir an, Sie haben ein Feld mit Namen und es gibt einen tschechischen Namen "Mořic", der ein r mit Caron enthält, den Sie mit Windows-1252 in eine csv-Datei exportieren müssen1 Kodierung. Dies wird fehlschlagen:

>>> Beispiel = 'Mořic'
>>> Beispiel.verschlüsseln('WINDOWS-1252')
UnicodeEncodeError: 'charmap' Codec kannt Zeichen verschlüsseln 'u0159' an Position 2: Das Zeichen wird auf  

Leider unterstützt Windows-1252 dieses Zeichen nicht, so dass eine Ausnahme ausgelöst wird. Wir brauchen also eine Möglichkeit, solche Kodierungsprobleme zu behandeln.

Kodierungsoptionen

Seit Python 3.32wird der Typ str in Unicode dargestellt. Unicode-Zeichen haben keine Darstellung in Bytes. Das ist die Aufgabe der Zeichenkodierung - eine Abbildung von Unicode-Zeichen auf Bytes. Jede Kodierung handhabt die Abbildung anders, und nicht alle Kodierungen unterstützen alle Unicode-Zeichen, was zu Problemen bei der Konvertierung von einer Kodierung in die andere führen kann. Nur die UTF-Familie unterstützt alle Unicode-Zeichen. Die am häufigsten verwendete Kodierung ist UTF-8, halten Sie sich also nach Möglichkeit an diese.

Mit str.encode haben Sie mehrere Optionen für die Fehlerbehandlung. Die Standardsignatur ist str.encode(encoding="utf-8", errors="strict"). Bei dem Beispiel "Mořic" lauten die Fehleroptionen:

Fehler WertBeschreibungErgebnis
strictKodierungsfehler lösen einen UnicodeError aus (Standard).Ausnahme
ignoreFehlerhafte Zeichen ignorieren.Moic
replaceErsetzen Sie fehlerhafte Zeichen durch ?.Mo?ic
xmlcharrefreplaceErsetzen Sie fehlerhafte Zeichen durch eine XML-Zeichenreferenz.Mořic
backslashreplaceErsetzen Sie fehlerhafte Zeichen durch eine Escape-Sequenz mit umgekehrtem Schrägstrich.Mou0159ic
namereplaceErsetzen Sie fehlerhafte Zeichen durch N{...} Escape-Sequenz.MoN{LATIN SMALL LETTER R WITH CARON}ic

Text-Normalisierung

Eine gute Alternative ist, die Daten zunächst mit unicodedata.normalize zu normalisieren. Der Unicode-Standard definiert einige Zeichen als aus mehreren anderen Zeichen zusammengesetzt. Zum Beispiel ist "ř" zusammengesetzt aus "r"(lateinischer Kleinbuchstabe r (U+0072)) und "ˇ"(Kombinationskaron (U+030C)). Nicht alle Webseiten mit Zeicheninformationen zeigen diese Informationen, aber z.B. diese Seite zeigt die zusammengesetzten Zeichen und Normalisierungsformen an: chars.suikawiki.org/char/0159.

Die Normalisierung kann in vier Formen angewendet werden:

Normale FormVollständiger Name
NFDNormalisierungsform Kanonische Dekomposition
NFCNormalisierungsform Kanonische Komposition
NFKDNormalisierung Form-Kompatibilitäts-Zerlegung
NFKCNormalisierung Form Kompatibilität Zusammensetzung

Um Unicode-Normalformen zu verstehen, benötigen wir zunächst ein paar Hintergrundinformationen.

Unicode und zusammengesetzte Zeichen

In Unicode werden die Zeichen auf so genannte Codepunkte abgebildet. Jedes Zeichen im Unicode-Universum3 wird durch einen Codepunkt, geschrieben als U+, und vier hexadezimale Ziffern ausgedrückt; z.B. steht U+0061 für ein kleines "a".

Der Unicode-Standard bietet zwei Möglichkeiten zur Angabe von zusammengesetzten Zeichen:

  1. Zerlegt: als eine Folge von kombinierten Zeichen
  2. Vorkomponiert: als ein einziges kombiniertes Zeichen

Zum Beispiel wird das Zeichen "ã" (Kleinbuchstabe a mit Tilde) in zerlegter Form als U+0061 (a) U+0303 (˜), oder in vorkomponierter Form als U+00E3 (ã) angegeben.

Zusammensetzung und Zersetzung

Unter Komposition versteht man die Kombination mehrerer Zeichen zu einem einzigen Zeichen, in der Regel ein Grundzeichen und ein oder mehrere Zeichen.4. Die Zerlegung ist der umgekehrte Vorgang: ein zusammengesetztes Zeichen wird in mehrere Zeichen zerlegt.

Bevor wir uns mit der Normalisierung befassen, sollten wir eine Funktion definieren, die die Unicode-Codepunkte für jedes Zeichen in einer Zeichenkette ausgibt:

>>> def Unicodes(String):
>>>     return ' '.beitreten('U+{:04X}'.Format(ord(c)) für c in String)
>>>
>>> Beispiel = 'Mořic'
>>> drucken(Unicodes(Beispiel))
U+004D U+006F U+0159 U+0069 U+0063

Kanonische und Kompatibilitäts-Äquivalenz

Ein Problem ergibt sich, wenn Zeichen mehrere Darstellungen haben. Zum Beispiel kann das Ångström-Symbol Å (eine Ångström-Einheit entspricht einem Zehnmilliardstel Meter) auf drei Arten dargestellt werden:

U+212B
U+00C5
U+0041 U+030A

Wie können wir feststellen, ob Zeichenketten gleich sind, wenn ihre zerlegten Formen unterschiedlich sind? Die Unicode-Äquivalenz wird auf zwei Arten definiert:

  1. Kanonische Äquivalenz
  2. Gleichwertigkeit der Kompatibilität

Wenn ein Zeichen aus verschiedenen Codepunkten das gleiche Aussehen und die gleiche Bedeutung hat, wird es als kanonisch äquivalent betrachtet. Zum Beispiel haben alle drei Darstellungen des obigen Ångström-Beispiels das gleiche Aussehen und die gleiche Bedeutung und sind daher kanonisch äquivalent.

Kompatibilitätsäquivalenz ist definiert als eine Folge von Codepunkten, die nur die gleiche Bedeutung haben, aber visuell nicht gleich sind. Zum Beispiel werden Brüche als kompatibel äquivalent betrachtet: ¼ (U+00BC) und 1⁄4 (U+0031 U+2044 U+0034) haben nicht dasselbe visuelle Erscheinungsbild, haben aber dieselbe Bedeutung und sind daher kompatibel äquivalent.

Die Kompatibilitätsäquivalenz wird als schwächere Äquivalenzform und als Teilmenge der kanonischen Äquivalenz betrachtet. Wenn ein Zeichen kanonisch äquivalent ist, ist es auch kompatibilitätsäquivalent, aber nicht andersherum.

Anwendung von Unicode-Normalisierungsformen

Mit diesen Hintergrundinformationen können wir nun zu den Unicode-Normalformen übergehen. Anhand des Beispiels "Mořic" am Anfang können wir eine Normalisierung vornehmen, bevor wir diese Zeichenfolge mit Windows-1252 kodieren:

>>> importieren Unicode-Daten
>>>
>>> def Unicodes(String):
>>>     return ' '.beitreten('U+{:04X}'.Format(ord(c)) für c in String)
>>>
>>> Beispiel = "Mořic"
>>>
>>> drucken(Unicodes(Beispiel))
U+004D U+006F U+0159 U+0069 U+0063
# 5 Unicode-Codepunkte, also wird das ř in vorkomponierter Form angegeben

>>> Beispiel.verschlüsseln("WINDOWS-1252")
UnicodeEncodeError: 'charmap' Codec kann nicht verschlüsseln Zeichen 'u0159' in Position 2: Zeichen Karten zu undefiniert>
# Windows-1252 kann U+0159 (ř) nicht kodieren.

>>> nfd_example = unicodedata.normalisieren("NFD", Beispiel)
>>> drucken(Unicodes(nfd_example))
U+004D U+006F U+0072 U+030C U+0069 U+0063
# 6 Unicode-Codepunkte, also wird das ř in zerlegter Form angegeben

>>> drucken(nfd_example)
Mořic
# Python-Shell mit UTF-8-Kodierung zeigt immer noch das r mit Caret an.

>>> nfd_example.codieren("WINDOWS-1252")
UnicodeEncodeError: 'charmap' Codec kann nicht verschlüsseln Zeichen 'u030c' in Position 3: Zeichen Karten zu undefiniert>
# Windows-1252 kann jetzt U+0072 (r) kodieren, aber nicht U+030C (ˇ)

>>> drucken(nfd_example.codieren('WINDOWS-1252', 'ignorieren'))
Moralische
# Windows-1252 erfolgreich kodiert und U+030C (ˇ) ignoriert.

Das war's! Mit unicodedata.normalize("NFD", "Mořic").encode('WINDOWS-1252', 'ignore') können wir zuerst normalisieren und dann Windows-1252 kodieren, wobei die unbekannten Zeichen für Windows-1252 ignoriert werden, was zu Moric führt. Ich mag diese Alternative, normalerweise sind die Leute damit einverstanden, da es die Daten nicht zu sehr vermischt und sie lesbar bleibt.

Verbessern Sie Ihre Python-Kenntnisse, lernen Sie von den Experten!

Bei GoDataDriven bieten wir eine Vielzahl von Python-Kursen für Anfänger und Experten an, die von den besten Fachleuten auf diesem Gebiet unterrichtet werden. Kommen Sie zu uns und verbessern Sie Ihr Python-Spiel:

Referenzen


  1. Windows-1252 war der erste Standardzeichensatz in Microsoft Windows und daher werden Sie ihn in vielen älteren Windows-Systemen finden. Der Standard für Windows-Systeme ist heute UTF-16 .
  2. Vor Python 3.3 war str ein Byte-String (eine Folge von Bytes in einer bestimmten Kodierung, standardmäßig ASCII) und unicode ein Unicode-String.
  3. Genauer gesagt ist das "Unicode-Universum" die Unicode-Zeichendatenbank (Unicode Character Database, UCD), die alle Unicode-Zeichen sowie deren Eigenschaften und Metadaten enthält.
  4. Unicode kategorisiert die Zeichen. Jede Kategorie wird durch eine Abkürzung aus zwei Buchstaben bezeichnet, wobei der erste ein Großbuchstabe und der zweite ein Kleinbuchstabe ist. Der Großbuchstabe steht für die Hauptkategorie, der Kleinbuchstabe für die Nebenkategorie. Die Hauptkategorie für Marken ist "M" .

Contact

Let’s discuss how we can support your journey.