Zeichenkodierung bestimmt, wie ein Zeichen im Speicher zu einer Zahl wird. Die meisten Anzeigefehler – „ü“ statt „ü“, ein Fragezeichen statt eines Emojis – sind Kodierungsprobleme. Wer die Grundlagen kennt, findet die Ursache in Minuten statt Stunden.

Die grundlegende Trennung

Ein Computer kennt keine Buchstaben, sondern nur Zahlen. Drei Begriffe sind nicht dasselbe:

  • Zeichenvorrat: Welche Zeichen gibt es überhaupt – Buchstaben, Ziffern, Symbole, Emojis?
  • Kodepunkt: Die eindeutige Nummer eines Zeichens im Vorrat. Bei Unicode wird sie als U+00FC geschrieben – das ist „ü“.
  • Kodierung: Wie diese Nummer als Bytes gespeichert wird. Für Unicode gibt es mehrere Verfahren: UTF-8, UTF-16, UTF-32.

Der letzte Punkt ist der häufigste Stolperstein: Unicode legt die Nummern fest, aber nicht, wie sie im Speicher liegen. Genau daraus entstehen die Anzeigefehler.

Der historische Weg zu Unicode

Früher gab es eine eigene Tabelle je Sprachraum, in der jedes Zeichen genau ein Byte belegte – 256 mögliche Zeichen.

  • ASCII: Die ersten 128 Werte (0–127). Enthält englische Buchstaben, Ziffern, Satzzeichen und Steuerzeichen. International bis heute der gemeinsame Kern.
  • ISO 8859-1 (Latin-1): Die oberen 128 Werte (128–255) für westeuropäische Zeichen – darunter ü, ö, ä, ß. Das Problem: Für griechische, kyrillische oder asiatische Zeichen brauchte es jeweils eine eigene Tabelle. Dieselbe Bytefolge bedeutete je nach Tabelle etwas anderes.
  • Windows-1252: Eine Abweichung von Latin-1, bis heute in einigen Windows-Programmen und alten Datenbanken zu finden.

Unicode und UTF-8

Unicode löst das Grundproblem: Ein Zeichenvorrat für alle Sprachen und Symbole, mit über 150.000 Zeichen. UTF-8 ist das Verfahren, diese Zeichen als Bytes abzulegen – und hat sich überall durchgesetzt.

Zeichen  Kodepunkt   UTF-8 Bytes          Laenge
A        U+0041      41                   1 Byte
ü        U+00FC      C3 BC                2 Byte
€        U+20AC      E2 82 AC             3 Byte
中       U+4E2D      E5 B8 AD             3 Byte
Grinsen  U+1F600     F0 9F 98 80          4 Byte

Die Eigenschaften, die UTF-8 zum Standard gemacht haben:

  • Kompatibel mit ASCII: Die ersten 127 Zeichen belegen genau ein Byte mit demselben Wert. Eine UTF-8-Datei mit rein englischem Text ist eine gültige ASCII-Datei – alte Programme arbeiten unverändert weiter.
  • Selbstsynchronisierend: Ein Byte ab 0x80 ist nie ein Einzelzeichen, sondern Teil eines Mehrbytezeichens. Nach einem Fehler findet ein Programm die Grenze zum nächsten Zeichen selbst wieder.
  • Variable Länge: Westlicher Text bleibt kompakt (ein Byte je Zeichen), nur selten gebrauchte Zeichen kosten mehr.
  • Keine Byte-Reihenfolge: Anders als bei UTF-16 ist keine Angabe nötig, ob zuerst das höher- oder niedrigwertige Byte kommt.

Ein Irrtum ist wichtig zu korrigieren: Ein Zeichen ist nicht gleich ein Byte. Die Länge in Zeichen, die Länge in Bytes und die Anzeigebreite sind drei verschiedene Zahlen – für Emojis sogar noch eine vierte, weil viele aus mehreren Kodepunkten bestehen.

Die Byte-Order-Mark (BOM)

Eine Datei kann mit den Bytes EF BB BF beginnen – der BOM. Sie zeigt die Kodierung an, ist aber selbst kein Zeichen. Windows-Programme schreiben sie oft.

# BOM in einer Datei erkennen
hexdump -C datei.txt | head -1
#   ef bb bf 48 61 6c 6c 6f   ....Hello

# BOM entfernen
sed -i '1s/^\xEF\xBB\xBF//' datei.txt
# In Python
python3 -c "
p='/tmp/d.txt'
d=open(p,'rb').read()
open(p,'wb').write(d[3:] if d.startswith(b'\xef\xbb\xbf') else d)
"

# Wo BOM schadet:
#   - Shell-Skripte: #!/usr/bin/env bash wird nicht erkannt
#   - Konfigurationsdateien: der erste Schluessel enthaelt unsichtbare Bytes
#   - JSON und CSV in Programmen, die den BOM nicht erwarten

Kodierung umwandeln und prüfen

# Vermutung pruefen (sehr verlaesslich)
file -i datei.txt
file datei.txt

# Von Latin-1 nach UTF-8 wandeln
iconv -f ISO-8859-1 -t UTF-8 alt.txt -o neu.txt

# Unbekannte Kodierung durchprobieren und Fehler melden lassen
iconv -f WINDOWS-1252 -t UTF-8 eingabe.txt > /dev/null
# Fehlerausgabe zeigt, welche Stelle nicht passt

# Zeichen und Kodepunkte ansehen
python3 -c "
s='Grüße'
print([hex(ord(c)) for c in s])          # ['0x47','0x72','0xfc','0xdf','0x65']
print(s.encode('utf-8').hex(' '))        # 47 72 c3 bc c3 9f 65
print(len(s), len(s.encode('utf-8')))    # 5 Zeichen, 7 Bytes
"

# Datenbank- und Serverkodierung pruefen
psql -c "SHOW server_encoding;"
mysql -e "SHOW VARIABLES LIKE 'character_set%';"
locale

Die typischen Fehlerbilder

Aus der Art der falschen Anzeige lässt sich die Ursache meist direkt ableiten:

  • „ü“ statt „ü“: UTF-8-Bytes wurden als Latin-1 gelesen. C3 BC ist in Latin-1 zweimal „ü“. Das ist der häufigste Fall – und immer eine Angabe im Ausgabeformat, nicht ein Datenverlust.
  • „ü“ statt „ü“: Der umgekehrte Fall – Latin-1-Bytes wurden als UTF-8 interpretiert.
  • Fragezeichen oder schwarze Rauten: Die Zeichen sind beim Umwandeln tatsächlich verloren gegangen. Hier ist Datenreparatur nötig, keine Einstellung.
  • Ersatzzeichen U+FFFD: Ein Programm hat auf nicht deutbare Bytes gestoßen und sie ersetzt. Die Originaldaten sind unbrauchbar – von einer Sicherung zurückholen.
  • Abgeschnittener Text bei Umlauten: Wenn nach einer festen Bytezahl abgeschnitten wird, kann ein Mehrbytezeichen halbiert werden. Immer nach Zeichen zählen, nicht nach Bytes.

Regeln für die Praxis

  1. Immer ausdrücklich UTF-8 verwenden – in der Datenbank, in der Anwendung, im HTTP-Kopfzeilenfeld Content-Type: text/html; charset=utf-8 und in der HTML-Datei <meta charset="utf-8">.
  2. Niemals auf die Standardkodierung verlassen. Beim Öffnen von Dateien in Python immer encoding="utf-8" angeben. Der Standard ist plattformabhängig und ändert sich zwischen Versionen.
  3. Beim Lesen mit „Fehler melden“ arbeiten, nicht stillschweigend ersetzen. Ein errors="replace" macht die Anzeige lesbar und verbirgt das Problem.
  4. Byte-Grenzen respektieren. Beim Zerschneiden von Text – etwa für Textabschnitte in einem KI-System – nach Zeichen arbeiten, nicht nach Bytes.
  5. Eine Datei, ein Format. Der Versuch, eine Latin-1-Datei durch Raten wiederherzustellen, ist fast immer vermeidbar: file -i liefert die Antwort.
  6. Länge richtig messen. Für „hat das Feld genug Platz?“ ist die Zeichenzahl relevant, für „wie viel Speicher braucht es?“ die Bytezahl, für die Anzeige die Breite. Drei verschiedene Zahlen für denselben Text.

Verwandte Grundlagen: Bits und Bytes, Zahlensysteme und Hexadezimal, JSON, API.