You are hereHome / Webentwicklung / UTF-8, Latin1 aka ISO-8859-1 und das Euro-Zeichen

UTF-8, Latin1 aka ISO-8859-1 und das Euro-Zeichen


By Gerd Riesselmann - Posted on 18 November 2006

Um mal gleich mit der Tür ins Haus zu fallen: Es gibt kein Euro-Zeichen im ISO-8859-1-Zeichensatz (aka Latin1) - und folglich sind alle Versuche, einen Text mit dem niedlichen Kniddel-E von UTF-8 oder jedem anderen Zeichen-Encoding nach Latin1 zu konvertieren zum Scheitern verurteilt. Mit etwas Glück kommt dabei ein Fragezeichen oder immerhin noch Gekröse raus. Korinthenkacker wie iconv dagegen stellen einfach ganz die Arbeit ein und man endet in einem Fehler.

Interesse an der ganzen Geschichte (die Lösung wird auch verraten)?

Latin1 soll also kein Euro-Zeichen enthalten, hmm? Warum kann ich dann das "€" in Webseiten sehen, die ISO-8859-1 kodiert sind?

Tja... Sagen wir mal so: Es ist heute ganz einfach, durch ganz Europa zu reisen und seine Euros fröhlich überall auszugeben. Das heißt aber nicht, dass ein Grenzer einen nicht trotzdem stundenlang mit Formalitäten an der Grenze festhalten könnte.

Das ist bei Computern nicht groß anders: Es gibt freundliche Programme, die versuchen, das Leben angenehm zu machen, etwa indem sie Konventionen gelten lassen. Eine solche Konvention sagt, das man das Zeichen 128 im Latin1-Zeichensatz durch das Euro-Symbol ersetzt hat.

"Man" ist in diesem Fall eine große Koalition aus Software- und Hardware-Herstellern. Schließlich musste bei der Einführung des Euros eine einfache und billige Lösung her. Die Vorteile liegen auf der Hand: die Programme selber müssen nicht geändert werden, es braucht lediglich eine neue Schrift. Die Nachteile der Lösung kennt jeder, der beim Drucken auf älteren Druckern auf die installierten Schriften des Druckers zurück greifen muss, die das Euro-Zeichen leider nicht kennen.

Auf der anderen Seite gibt es Programme, die penibel auf die Einhaltung der Regeln pochen: bürokratisch, humorlos. Wie zum Beispiel die Programme, die Zeichenkodierungen konvertieren.

Diese argumentieren, ISO-8859-1 enthalte ganz offensichtlich kein Euro-Zeichen (bei der Festlegung von ISO-8859-1 gab es noch keinen Euro) und gleich dreimal nicht an Position 128. Stattdessen gäbe es doch die Kodierung ISO-8859-15, diese definiere ein Euro-Symbol und sei doch auch bereits seit 1999 gültig.

Und das ist natürlich nicht verkehrt. ISO-8559-15 enthält einen Euro, und zwar an Position 164. Damit sind ISO-8859-15 und ISO-8859-1 (Euro-tauglich) euro-mäßig wiederum nicht kompatibel. Das wäre ja auch zu einfach, erklärt sich aber vielleicht daraus, dass bei Latin1 an Position 164 noch dieses Zeichen steht: ¤. Das ist das internationale Währungszeichen - süß, nicht wahr? Besser bekannt ist dieses Zeichen freilich als Tabellenzellen-Ende-Zeichen aus Microsoft Word und anderen Textverarbeitungen. Genau so gut hätte man vorschlagen können, das Symbol ¶ durch den Euro zu ersetzen.

ISO-8859-15 jedenfalls ist ein lustiger Geselle, von dem man noch nicht mal weiß, ob er nun Latin0 oder Latin9 heißt. Man weiß jedoch, dass er eigentlich Latin1 hatte ersetzen sollen. Daraus ist allerdings nichts geworden, wenn wir uns zum Beispiel PHP, QT oder andere Programmiersprachen und -frameworks ansehen. Latin1 ist immer noch omnipräsent.

Wer sich aber Ärger ersparen will, der greift fortan auf ISO-8859-15 zurück.

Aus all dem folgt also, dass Code wie der folgende - der einen UTF-8 Text annimmt und eine Latin1-Mail verschickt - in die Katastrophe führen, wenn der Text ein Euro-Zeichen enthält:

<?php
function send_mail($to, $subject, $utf8_message) {
 
//falsch!
 
$latin_message = @iconv('UTF-8', 'ISO-8859-1', $utf8_message);
 
// auch falsch!
 
$latin_message = @utf_decode($utf_message);
 
mail($to, $subject, $latin_message);
}
?>

Hier ist die richtige Version. Da wir latin0-oder-9 verwenden, müssen wir das beim Verschicken der Mail irgendwie mitteilen, also auch einen entsprechenden Header dazupacken:

<?php
function send_mail($to, $subject, $utf8_message) {
 
$latin_message = @iconv('UTF-8', 'ISO-8859-15', $utf8_message);
 
$header = 'Content-Type: text/plain; charset=ISO-8859-15';
 
mail($to, $subject, $latin_message, $header);
}
?>

Oder eben gleich die Mail in UTF-8 versenden.

Ist doch nur ein Beispiel... Außerdem unterstützt Eudora immer noch kein UTF-8.

Kann Outlook (Express) das denn inzwischen?

Achso, btw. Ich tendiere ja inzwischen dazu, auch für die einfachste Sache der Welt© irgendwelches Komponenten-Gedöns zu verwenden. Früher habe ich für das Versenden von Mails immer ezMail verwendet, heute eher Zend_Mail. Das ist vor allem auch dann praktisch, wenn das System in Environments laufen soll, die nicht unbedingt gerade ein sendmail-Binary rumliegen haben. Die können nämlich meist immer noch gleich Adapter für das Versenden von Emails, am ausgereiftesten sehe ich das in ezMail. Damit kann man ausgesprochen hübsch sagen, »Hey, sende die Mail doch mal via SMTP«. Ansonsten solltest du vielleicht noch überprüfen, ob die iconv()-Konvertierung überhaupt klappt $string = @iconf(...); if ($string !== false) { ... }, wenn du irgendwie nicht ganz sicher sein kannst, dass der Content der da rein läuft auch sauberes UTF-8 ist.

@iconv(...) liefert im Misserfolgsfall nicht false zurück, sondern bricht beim ersten nicht-konvertierbaren Zeichen ab:

<?php
$s
= @iconv('Zahle bitte 10 € für nix an mich');
print
$s;
?>

gibt aus:

Zahle bitte 10

Ansonsten sind Komponenten natürlich nie verkehrt..., auch wenn ich sie immer noch mal mit einer eigenen Klasse umwickeln würde. Ich habe meine persönliche Mailklasse jetzt dermaßen geändert, UTF-8 zu verschicken und einen Latin/0/9/ISO-8859-15-Anhang dranzupacken für die paar unverbesserlichen Nostaliker. Wenn der Anhang aus irgendwelchen Gründen trotzdem geschreddert wird, who cares?

Guter Beitrag! Ich hab da nur einen kleinen Tippfehler beim Setzen von $header entdeckt (die letzte Klammer ist überflüssig). Ansonsten ist er sehr informativ.

Im Grunde war ich auf der Suche nach einer Lösung für folgendes Problem: Die Daten werden in UTF-8 geliefert (Website) und die Tabellen in der Datenbank sind auf Latin-1 eingestellt. Das Problem an der Stelle ist nur das Eurozeichen welches den Konvertierungen mit iconv() nicht standhält.

Die Lösung des Problems heisst entweder die Website auf iso-8859-1 umzustellen, oder die Datenbank auf UTF-8 zu konvertieren.

Danke für den Hinweis, ist korrigiert.

Du kannst auch von UTF-8 nach ISO-8859-15 konvertieren und anschließend das internationale Währungszeichen ¤ durch € ersetzten. Dann hast du nachher Latin-1 mit Euro-Zeichen.

Es ist aber auf jeden Fall besser, einmalig die Tabellen auf UTF-8 umzustellen :-)