Grundsätzliches zum Umgang mit Encoding

Wer Verständnisschwierigkeiten mit der Encoding-Problematik hat, kann sich vielleicht damit trösten, dass auch die Verantwortlichen nicht immer sofort den besten Ansatz gefunden haben. In Anbetracht sich teilweise widersprechender Informationen und Empfehlungen bleibt festzuhalten, dass der Trend ganz offensichtlich in Richtung UTF-8 geht. War in älteren Dokumenten noch oft von ISO-8859-1 als Defaultwert die Rede, wurde die Überlegenheit des konzeptionellen Ansatzes von Unicode mittlerweile offensichtlich erkannt. Es ist jedoch leider z.T. wirklich schwer herauszubekommen, welche Vorgaben die Standardisierungsgremien denn nun wirklich machen.

Betriebssysteme

Manche Betriebssysteme (z.B. unix-artige) bieten verschiedene Konfigurationsmöglichkeiten zum Einstellen des grundsätzlich verwendeten Encodings an. Diese Einstellung beeinflusst das Verhalten eines Systems in mancherlei Hinsicht:

Wenn das Betriebssystem diese Einstellungsmöglichkeit bietet, sollte man auf jeden Fall das Default-Encoding auf eine Unicode-Repräsentation einstellen. Natürlich kann das dazu führen, dass in der Vergangenheit angelegte Dateien mit Umlauten oder Sonderzeichen im Namen nun vom Betriebssystem nicht mehr fehlerfrei angezeigt werden können. Das betrifft dann sowohl die Anzeige der Datei im Filebrowser als auch die Rückgabewerte der entsprechenden Systemroutinen etwa beim Auslesen eines Verzeichnisse. Bei eigenen Dateien kann man diese natürlich einfach umbenennen. Das Aufspüren der Dateien kann im Bedarfsfall programmatisch erfolgen (etwa mit Hilfe eines Perl-Skripts), eventuell sogar die Umkodierung selbst.

Größere Schwierigkeiten entstehen, wenn manche Fremd-Applikationen (sprich: installierte Programme) in ihren Dateinamen etwa Copyright oder andere Sonderzeichen verwenden. Ein Umkodieren könnte in diesem Fall die Funktionstüchtigkeit der Applikation gefährden. Hier gilt: Ausprobieren (Backup nicht vergessen) und gegebenenfalls beim Hersteller der Software beschweren.

Die meisten Linux-Distributionen werden heutzutage mit UTF-8 als Default-Encoding ausgeliefert, hier besteht im allgemeinen kein Handlungsbedarf. Nähere Informationen gibt es etwa in dem leider nicht mehr ganz aktuellen Linux HowTo aus dem Jahre 2001(!) oder dieser FAQ-Sammlung.

Leider kann ich zu anderen Betriebssystemen nur wenig Aussagen machen, es ist aber zu erwarten, dass sowohl Solaris als auch die verschiedenen BSD-Betriebssysteme UTF-8 gut unterstützen. Ähnliches gilt natürlich auch für MacOS X mit seinem BSD-Unterbau. Zum Thema Windows Betriebssysteme liegen mir leider keine Informationen vor.

Vorgaben und Empfehlungen aus dem Umfeld des W3C

Obwohl UTF-8-kodierte Zeichen im Gegensatz etwa zu UTF-16 unabhängig von der Byteordnung (Endianness) sind, erlaubt die XML-Spezifikation explizit einen Byte Order Marker (BOM) auch für UTF-8 kodiertes XML. Es ist jedoch nicht empfehlenswert, diesen für UTF-8 zu verwenden: er wird nicht benötigt und kann allenfalls Probleme verursachen.

Eine URL darf ausschließlich ASCII-Zeichen enthalten. In RFC 2718 wird empfohlen, Sonderzeichen in einer URL, die nicht in ASCII darstellbar sind, mittels %HH byteweise zu kodieren, wobei HH die Hexadezimaldarstellung eines Bytes der UTF-8-Kodierung eines Sonderzeichens ist. Ein ä in UTF-8 müsste somit folgerichtig in einer URL als %C3%A4 (zwei Bytes) kodiert werden. Leider ist in der URI-Spezifikation (die auch URLs umfasst) RFC 2396 aus historischen Gründen nicht explizit festgelegt, in welcher Kodierung die Hexadezimaldarstellung von Nicht-ASCII-Zeichen vorzunehmen ist. Siehe hierzu auch eine Empfehlung des W3C.

In RFC 2396 wird das Nichtspezifizieren der Basis der hexadezimalen %HH Escape-Sequenzen von folgender Bemerkung begleitet:
It is expected that a systematic treatment of character encoding within URI will be developed as a future modification of this specification.

HTTP-GET-Parameter werden in der URL übertragen und dürfen daher auch lediglich ASCII-Zeichen enthalten, Sonderzeichen in den Variablennamen oder -werten sind mittels %HH zu escapen.

HTTP-POST-Parameter können beliebige Zeichen enthalten, auf das verwendete Encoding kann über das Attribut enctype für das <FORM>-Tag Einfluss genommen werden. Laut W3C Recommendation sollten POST-Parameter, die mit enctype="multipart/form-data" verschickt werden, das volle Unicode-Spektrum abdecken können.

Zum Thema GET- und POST-Parameter siehe auch folgendes Dokument.

Im RFC 2616 ist festgelegt, dass bei Nichtspezifizieren des Parameters charset der Wert ISO-8859-1 als Defaultwert für alle Inhalte mit dem Medientyp text angenommen wird. Damit werden also alle HTML-Seiten, in denen das Encoding nicht mit Hilfe des charset-Parameters explizit spezifiziert wird, als ISO-8859-1 kodiert angesehen. Diese Spezifikation stammt aus dem Jahre 1999, ich vermute, dass heutzutage die Wahl auf UTF-8 fallen würde (oder besser gesagt: ich hoffe es).

Grundsätzliche Vorsichtsmaßnahmen zur Vermeidung von Encoding-Problemen

Erster Schritt für den Weg in eine bessere Zukunft mit problemlosem Austausch von Texten zwischen verschiedenen Beteiligten ist eine konsequente Kennzeichnung der Kodierung von Textdateien. Das geschieht heutzutage für High-Level-Dokumente in Textverarbeitungssystemen oder Email-Browsern meist automatisch, gegebenenfalls muss man das Mailprogramm entsprechend konfigurieren. Aber auch bei einfachen Konfigurationsdateien oder kleinen, unformatierten Texten ist es für Leute, die damit arbeiten müssen, immer gut zu wissen, ob man Umlaute oder Sonderzeichen problemlos einfügen könnte. Daher gilt: eine kurze Anmerkung als Kommentar im Kopf der Datei (falls möglich) oder eine kurze Erwähnung der zu verwendenden Kodierung in der Dokumentation ist immer eine gute Idee.

Wenn man Sonderzeichen im Sourcecode verwendet, sollte man sicherstellen, dass niemand beim Editieren versehentlich das Encoding der Source-Datei überschreibt!

Grundsätzlich ist zu bedenken: mit UTF-8 sind theoretisch alle bekannten Zeichen darstellbar, auch alle fernöstlichen Dialekte oder historische Sprachen, wie etwa Keilschrift. Probleme kann es höchstens noch geben, wenn etwa nicht die korrekten Fonts zur Darstellung installiert sind. Entscheidet man sich jedoch für ein ISO-8859-x Encoding, ist das gemeinsame Auftreten bestimmter Zeichen (etwa bestimmter russischer und griechischer Buchstaben) in einem Text nicht möglich. Daher ist UTF-8 zur Datenrepräsentation immer eine gute Wahl!

Manche Sprachen, wie zum Beispiel HTML, haben optionale Tags zur Spezifizierung der verwendeten Kodierung. Es ist eine gute Angewohnheit, diese zu verwenden und explizite Angaben im Quellcode zu machen. Damit erhöht man die Wahrscheinlichkeit, dass die eigene Seite in keinem Browser falsch dargestellt wird, obwohl es an dieser Stelle leider keine hundertprozentige Sicherheit gibt (dazu unten mehr in den Anmerkungen zur Konfiguration eines Webservers).

Bei der Wahl des Texteditors ist es wichtig, darauf zu achten, dass dieser ordentlich mit Unicode-Zeichensätzen umgehen kann. Falls der Editor eine Datei fehlerhaft darstellt, sollte man immer zunächst eine Sicherheitskopie dieser Daten erstellen, bevor man versucht, die Einstellungen im Editor zu ändern oder die Datei nochmals abspeichert. Es kann bei den Umwandlungen von einem Format ins andere (insbesondere bei Interpretation von ISO-8859-1 Zeichen als UTF-8) zu Datenverlust kommen, der nur schwer und von Hand reparabel ist.

Weiterhin ist natürlich eine erhöhte Sensibilität für die angesprochene Problematik vonnöten. Programmiersprachen, die Strings nicht auf einem geeigneten Abstraktionslevel darstellen (können), um dem Programmierer einen Teil der möglichen Probleme abzunehmen, sind besonders fehlerintensiv. Hier hilft nur eiserne Disziplin: wenn man Strings manipuliert, sollte man sich immer der Tatsache bewusst sein, dass ein Zeichen aus mehreren Bytes bestehen kann und entsprechend die speziellen Funktionen bevorzugen. Es gilt: die Darstellung mit einem Byte ist ein Spezialfall eines UTF-8-kodierten Strings und somit funktionieren dann auch die Multibyte Funktionen der Programmiersprache. Das Gleichsetzen von Zeichen (Buchstaben) und Bytes ist hingegen konzeptionell falsch und wird früher oder später zu Problemen führen, wenn man nicht absolut sicher sein kann, dass nur ASCII-Zeichen und bestimmte Sonderzeichen in den Texten vorkommen können.

Eine wesentliche Grundlage für korrektes Handling von Unicode (bei manchen Programmiersprachen sogar die einzige Voraussetzung) ist das korrekte Einlesen der Daten von Festplatte und evtl. das spätere Zurückschreiben. Hier werden von manchen Programmiersprachen (angeblich kluge) Annahmen getroffen, wenn der Benutzer beim Einsatz der IO-Operationen nicht explizit festlegt, in welchem Encoding die Daten vorliegen. Dieses Verhalten erweist sich jedoch nur allzu gerne als Bumerang: viele Programmierer sind sich überhaupt nicht der Tatsache bewusst, dass sie an dieser Stelle besser selber die Entscheidung treffen sollten. Wenn dann dasselbe Programm auf einem anders konfigurierten System seltsame Fehler hervorruft, ist aufwändige Fehlersuche angesagt. So verwendet etwa Java die Heuristik: wenn keine expliziten Angaben gemacht werden, erfolgt das Einlesen einer simplen Textdatei in einem Encoding, das aus den Spracheinstellungen des Betriebssystem geraten wird. Da kann man den Programmierern eigentlich noch nicht mal böse sein, wenn das schiefläuft. In der heutigen Zeit ist ein solches Verhalten einfach nicht mehr angemessen in Anbetracht der zunehmenden Globalisierung von Texten durch das Internet.

Problemzonen

Folgende Fakten tragen meiner Meinung nach besonders zur Provokation von Encoding-Problemen bei:

Beobachtungen anhand von Test-Szenarios

Voraussetzung:
Zwei HTML-Seiten mit demselben eingebetteten PHP-Code, eine HTML-Seite in UTF-8 die andere in ISO-8859-1 (Einstellung über das entsprechende Meta-Tag), der PHP-Code gibt lediglich eine bestimmte GET-Variable namens 'x' aus.
Test:
Zugriffe von der URL-Leiste des Firefox mittels http://destination/testPage.php?x=ä
Anmerkungen:
  • Firefox setzt diese Anfrage immer in UTF-8 um, d.h. es wird http://destination/testPage.php?x=%C3%A4 daraus. Ist das evtl. konfigurierbar? Siehe auch folgende Seite zum Thema Mozilla Konfiguration. Diese Option war in meinem Firefox jedoch auf false gesetzt.
  • Folgerichtig wurde der Inhalt der GET-Variable 'x' in der UTF-8-Seite korrekt ausgegeben, in der ISO-8859-1-Seite jedoch nicht.
  • Wenn man die Kodierung in der URL-Leiste des Firefox selbst vornimmt und das ä hexadezimal in ISO-8859-1 kodiert, also http://destination/testPage.php?x=%E4, dann ist die PHP-Ausgabe in der ISO-8859-1-Seite korrekt, aber falsch in der UTF-8-Seite. Es fanden sich auch keinerlei Angaben zum Encoding im zugehörigen HTTP Request.
  • Interessant ist in diesem Zusammenhang auch RFC 3987.
Voraussetzung:
Java Server Page, auf die via Tomcat zugegriffen wird. Die Seite enthält ein Formular mit einem Textfeld, in dem der Benutzer Eingaben vornehmen kann. Die Eingaben des Benutzers werden dann beim Abschicken des Formulars einfach angezeigt. Die vom Servlet erzeugte HTML-Seite hat UTF-8-Encoding, im JSP-Code wurden Request und Response Objekte explizit mittels
  • response.setCharacterEncoding("UTF-8");
  • request.setCharacterEncoding("UTF-8");
gesetzt.
Test:
Eingabe von Sonderzeichen im Textfeld
Anmerkungen:
  • Die Umlaute werden falsch dargestellt, wenn Tomcat die Default-Konfiguration nutzt.
  • Abhilfe schafft hier nur das weiter unten erwähnte Setzen der Konfigurationsparameter useBodyEncodingForURI und URIEncoding.