ISO 8859-1, UTF-8 und Wordpress

(Theoretischen Teil überspringen und gleich zur Lösung der Aufgabe springen, die im Titel angekündigt wird. Aber das ist nur für technische Blogbastler interessant.)

Inzwischen ist aus einem kurzen Eintrag ein langer geworden, und er erklärt nicht mehr das, was er am Anfang sollte. Ich sollte ihn wirklich kürzen und neu strukturieren. Der Unterschied zwischen Profi und Amateur: ich werd’s einfach nicht tun. Trotzdem, für Informatik – Repräsentation von Information – wäre das schon praktisch.

1. Einführung

Wenn man am Computer etwas schreibt – im Textverarbeitungsprogramm oder im Blog – ist ein “a” nie nur ein “a”. Man drückt zwar die entsprechende Taste auf der Tastatur und ein “a” erscheint. Wenn man das dann speichert, wird ein “a” gespeichert. Sollte man meinen, aber das ist nicht so. Das hat jeder schon mal gemerkt, dem es die Umlaute beim Speichern verhagelt hat, oder der eine Mail kriegt, in der solche Sätze auftauchen:

ich w�rde es begr��en, wenn du mir nicht so etwas schreiben w�rdest

oder in der einem

Viele Grüße

gewünscht werden. (Sieht man auch immer wieder mal bei Track- oder Pingbacks in Blogs.)

Wer ist da schuld, was ist da passiert, wie kann man das vermeiden?

Einen ausgezeichneten Überblick zu diesem Thema gibt “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)”. Ich habe mich für diesen Artikel sehr bei ihm bedient – dort steht das alles noch viel ausführlicher und interessanter.

Hier eine Kurzfassung und ein paar wichtige Begriffe.

2. ASCII

Zeichen werden wie alles im Computer durch Zahlen repräsentiert. Ein früher Standard dazu hieß ASCII (Wikipedia). Nach diesem Kodierungssystem werden für jedes Zeichen 7 bit reserviert, was einen Vorrat von 128 möglichen Zeichen ermöglicht. Die Zeichen mit den Nummern 0 bis 31 sind Sonderfälle, sogenannte nicht druckbare Zeichen, aber von Nummer 32 bis 126 sehen die Zeichen vertraut aus:

 !"#$%&'()*+,-./0123456789:;<=>?   (Nr. 32-63)
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_   (Nr. 64-95)
`abcdefghijklmnopqrstuvwxyz{|}~    (Nr. 96-126)

Das Zeichen mit der Nummer 32 ist das Leerzeichen, das große A hat die Nummer 65, die Tilde ist die Nummer 126. (Die Nummer 127, das letzte der 128 ASCII-Zeichen, ist wieder ein Sonderfall.)

Gespeichert wird ein Wort, zum Beispiel “Abel”, als Folge der ASCII-Zeichen-Nummern: 65-98-101-108.

Allerdings fehlen bei diesem System europäische Sonderzeichen – Buchstaben mit Umlauten und Akzenten und noch exotischeres Zeug. Zur Lösung gab es zwei Möglichkeiten: Entweder man schafft einen eigenen europäischen ASCII-Dialekt, bei dem die Nummer 93 eben nicht für “]” steht, sondern für “Ü”. Dann können auch Deutsche wunderbar schreiben, müssen dafür aber auf eckige Klammern verzichten. Außerdem müssen sich Sender und Empfänger von Texten (und jedes Textverarbeitungsprogramm für sich) darüber verständigen, ob ein Dokument oder auch nur ein Wort in amerikanischem oder europäischem ASCII zu lesen sein soll. Sonst liest der Amerikaner versehentlich “]bel” statt “Übel”, wenn er eine europäische Datei oder Mail öffnet. Gespeichert wird das Wort ja als Folge der ASCII-Nummern der einzelnen Zeichen, also “93-98-101-108″, und ob das jetzt “]bel” oder “Übel” heißen soll, das kann der Computer nicht so einfach wissen, wenn man ihm es nicht sagt. Und ein Franzose oder Däne braucht wieder einen eigenen ASCII-Dialekt.

3. ISO 8859-1

Die andere Lösung war die, für jedes Zeichen 8 bit zu reservieren statt 7. Damit hat man immerhin einen Vorrat von 256 Zeichen zur Verfügung, muss also nicht zugunsten eines “Ü” auf ein “]” verzichten und kann beides benutzen. Die ersten 128 Zeichen blieben dabei parallel zu ASCII. Das ist praktisch, weil die in 7-bit-ASCII gespeicherten Dateien dann genauso gut von einem 8-bit-System gelesen werden können, ohne dass man irgendetwas umstellen muss.

Allerdings gibt es auch wieder verschiedene 8-bit-Varianten. MS-DOS hatte sein eigenes System, Windows wieder ein anderes. (Deshalb sehen die Umlaute in unter MS-DOS erzeugten Dateien falsch aus, wenn man die Dateien als übliche Windowsdateien betrachtet.)

Verbreitet ist heute ISO 8859-1 (“Latin 1″, Wikipedia). Da sind weiterhin für jedes Zeichen 8 bit reserviert; es gibt also 256 Zeichen, die ersten 128 entsprechen dabei ASCII – das ist praktisch. Man wird also weiterhin “65-98-101-108″ als “Abel” lesen. Zu den anderen Zeichen gehören europäische Umlaute, Zeichen mit Akzent, skandinavischen Zeichen, und andere. Aber auch nicht alle: das Euro-Zeichen gehört nicht dazu. Aber auch da gibt es Aushilfen (etwa ISO 8859-15), so dass ISO 8859-1 ausreicht für (laut Wikipedia):

Afrikaans, Albanisch, Baskisch, Dänisch, Deutsch, Englisch, Färöisch, Finnisch, Französisch, Irisches Gälisch, Isländisch, Italienisch, Katalanisch, Niederländisch, Norwegisch, Portugiesisch, Rätoromanisch, Schottisches Gälisch, Schwedisch, Spanisch, Swahili und Wallonisch.

Kyrillisch geht mit ISO 8859-5, Mitteleuropäisch (darunter Ungarisch, Tschechisch, Polnisch) mit ISO 8859-2.

Viele polnische Seiten sind also, vermuten wir erst einmal, in ISO 8859-2 kodiert. Da ist das Zeichen Nummer 163 das hier: “Ł”. (Wird die gespeicherte Seite als ISO 8859-1 interpretiert, würde an derselben Stelle das Zeichen mit der ISO-Nummer 163 aber so dargestellt werden: “£”.)
Man kann das schnell mal ausprobieren: in jedem Browser kann man von Hand die Kodierung einstellen, in Firefox unter “Ansicht/Zeichenkodierung”. Da kann man dieselbe Seite mal so betrachten, als sie in ISO 8859-2 geschrieben, mal als sei sie ISO 8859-1. (Beispiel: polnische Seite in ISO 8859-2 kodiert.)

Exkurs:

Aber woher weiß der Browser denn am Anfang, wie er die Seite darstellen soll. Ob der Seitenersteller ein “Ł” oder ein “£” darstellen will? Die Kurzfassung: im schlimmsten Fall rät er, aber normalerweise steht im Kopf einer sauber geschriebenen HTML-Seite, welche Kodierung der Browser zur Darstellung nehmen soll, etwa so:

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

(Bis zu dieser Stelle weiß der Browser aber noch nicht, wie die Seite kodiert ist, muss also stillschweigend davon ausgehen, dass er wenigsten diese Stelle schon mal richtig dekodiert hat. Interessante Frage, das.)

Quizfrage

Wie habe ich es denn geschafft, sowohl das Zeichen “Ł” als auch ein “£” auf dieselbe Seite zu kriegen? Beide Zeichen sind doch die Nummer 163? Das geht mit reinem ISO 8859-1 tatsächlich nicht, und mit reinem ISO 8859-2 ebensowenig. Eine Lösung bietet HTML: da gibt es die Möglichkeit, Zeichen direkt auszuwählen:

  • &Lstrok; wird in HTML immer so dargestellt: Ł
  • &pound; wird in HTML immer so dargestellt: £
  • &Auml; wird in HTML immer so dargestellt: Ä
  • &ouml; wird in HTML immer so dargestellt: ö

Das funktioniert immer und unabhängig von der Kodierung, jedenfalls solange das & und die folgenden Zeichen richtig erkannt werden, die deshalb alle aus dem gemeinsamen Zeichenvorrat kommen. Für viele Sonderzeichen gibt es in HTML solche festen Zeichen, hier eine Liste davon.

Das ist aber nicht die einzige Lösung für dieses Problem.

4. Unicode

Meine eigene Seite ist jetzt aber gar nicht mal in ISO 8859-1 kodiert, und die meisten polnischen Seiten, die ich gefunden habe, sind ebensowenig in ISO 8859-2 kodiert, sondern in wieder etwas anderem: UTF-8.

Um das zu erklären, muss ich etwas zu Unicode sagen. Unicode geht die Sache mit den Zeichen von einer anderen Seite aus an: jedes Zeichen auf der Welt kriegt eine eindeutige Unicode-Nummer, einen sogenannten code point. Das sind zur Zeit laut Wikipedia über 109.000 Zeichen aus 93 Alphabeten, einschließlich Linear B, Phönizisch und I-Ging-Hexagramme. Die Zeichen des Voynich-Manuskripts und Tengwar (Tolkiens Elbenschrift) sind aber noch nicht dabei; für letzteres läuft gerade ein Aufnahmeantrag.
Hier kann man sie sich alle anschauen. Platz ist im Unicode-System für mehr als eine Million Zeichen.

Das ist natürlich eine sprachwissenschaftlich und politisch nicht uninteressante Sache: was ist ein Buchstabe, was gehört zu einem Alphabet? Unicode wird deshalb auch kritisiert (Wikipedia deutsch, mehr bei englisch). Trotzdem ist das mit dem Unicode eine praktische Sache: jeder Buchstabe kriegt eine platonische Entsprechung als code point.

Der Buchstabe A des lateinischen Alphabets hat zum Beispiel den code point U+0041. Die Zahl ist dabei im Hexadezimalsystem zu lesen, 0041 entspricht im Dezimalsystem der Zahl 65. Wie schon damals im ASCII-Code… denn ja, die code points der lateinischen Buchstaben ohne diakritische Zeichen entsprechen den alten ASCII-Nummern.

Das Zeichen U+03B2 sieht bei mir im Browser so aus: β, das Zeichen U+00DF so: ß. In manchen Schriftarten mögen die Zeichen sehr ähnlich sein, aber die Codierung macht klar: das eine ist ein beta, das andere ein sz/scharfes s. Wenn für das Unicode-Zeichen in meinem Browser kein Zeichensatz vorgesehen ist, sieht man stattdessen so etwas Komisches wie hier bei U+010900, dem ersten Buchstaben des phönizischen Alphabets: 𐤀. Zur Darstellung müsste ich mir dann wohl mal einen passenden Zeichensatz herunterladen.

(Fußnote: Zeichensätze auch für exotischere Unicode-Codepoints findet man leicht. Code2000 bzw. desssen Nachfolger – Wikipedia dazu – werden wohl nicht mehr weiter aktualisiert, versuchen aber, möglichst viele Zeichen darzustellen.)

UTF-8

Unicode ist allerdings erst mal nur ein Verzeichnis aller Zeichen und eine eindeutige Zuweisung eines code points. Wie man das dann speichert, ist wieder eine andere Frage, unsere alte Frage von oben, nur dass ich halt nicht “A” einer Zahl zuordnen muss (z.B. A=>65), sondern “U+0041″ (z.B. U+0041=>65).

Da gibt es UTF-32, bei dem für jedes Zeichen 32 bit (4 Byte) reserviert werden. Damit kann man für jedes Zeichen aus einem Pool von 232 Buchstaben auswählen, also 4 294 967 296. Das reicht für alle Unicode-Zeichen, aber 32 bit pro Zeichen sind eine ganze Menge Platzverschwendung. Viel verbreiteter ist dagegen UTF-8: da sind die häufigsten Zeichen mit 8 bit kodiert – wir ahnen es schon, das sind unsere alten Freunde aus dem 7-bit-ASCII-Zeichensatz, nämlich die Unicode-Zeichen 0-127. Die weniger häufigen Zeichen sind dann im 16-bit-Bereich kodiert, darunter die Umlaute. Und die selteneren Zeichen sind bei UTF-8 mit bis zu vier Byte kodiert. Das heißt, dass ein Dokument aus hundert seltenen Zeichen viermal so viel Speicherplatz benötigen kann wie eines aus häufigen Zeichen. Selten jedenfalls aus amerikanischer Sicht.

(Fußnote: Hier sieht man die verschiedenen Kodierungsmöglichkeiten etwa von U+10900.)

5. MySQL-Datenbank von ISO auf UTF-8 umstellen, und wie ich überhaupt auf diesen Kram komme

Das Blogsystem Wordpress speichert die Beiträge nicht als Datei auf einer Festplatte ab, sondern in einer Datenbank. Aber auch dazu muss man wissen, welche Kodierung zum Speichern verwendet wird – damit man die gleiche Kodierung zum Lesen verwenden kann. Wenn ich ein Dokument in ISO 8859-1 in der Datenbank speichere und danach beim Herauslesen als UTF-8 interpretiere, kriege ich Schwierigkeiten bei den Umlauten und Sonderzeichen, andersrum natürlich ebenso.

Standardmäßig war früher bei Wordpress-Installationen ISO 8859-1 als Kodierung für die Datenbank eingestellt. Das heißt, wenn ich ein “A” getippt habe, wurde das letztendlich als 65 gespeichert (hexadezimal: 41), wenn ich ein “ö” getippt habe, dann wurde das letztendlich als 246 gespeichert (hexadezimal: F6). Wenn ich den in der Datenbank gespeicherten Eintrag dann wieder lese, wird die 65 als “A” interpretiert (in ISO, aber auch in UTF-8 und in ASCII), die 246 wird als “ö” interpretiert – aber eben nur in ISO, nicht in UTF-8, wo ein “ö” durch 50070 repräsentiert wird (hexadezimal: c396) und 246 überhaupt nicht definiert ist. Dann werden stattdessen kleine Rauten mit Fragezeichen darin angezeigt.

(MySQL-Experten mögen mir die grobe Vereinfachung verzeihen.)

Inzwischen ist die Standard-Kodierung bei Wordpress-Installationen UTF-8. Und das hat bei meinem ISO-Wordpress zu Problemen geführt. Ich weiß auch nicht, woran das liegt – aber immer wieder mal ist ein Blogbeitrag beim Speichern falsch kodiert worden. Alle Umlaute hat’s mir verhagelt. Das war sehr lästig. Auf dieser Tabelle sieht man links das geschriebene Zeichen (ISO), rechts das, was gespeichert wurde (nämlich fälschlicherweise als UTF). Ich tippte ein “ü”, das nach ISO-Kodierung letztendlich als (hexadezimal) fc gespeichert werden müsste, tatsächlich wurde es aber nach UTF-Kodierung letzendlich als (hexadezimal) c3bc gespeichert – und aus diesen zwei Byte werden, wenn man das dann als ISO liest, eben à und ¼.

Also wollte ich meine Datenbank von ISO auf UTF-8 umstellen. Das ist aber gar nicht so einfach. Es gibt eine Reihe von Plugins dazu. Ich habe einige davon ausprobiert; sie funktionieren alle nicht. Das steht auch so bei Wordpress selber, wo diese Seite eine Anleitung dazu gibt, wie man die Kodierung der Datenbank umstellt:

https://codex.wordpress.org/Converting_Database_Character_Sets

Und die Seite ist gespickt mit: “Tu’s nicht” und “Es ist schwierig”, und das ist tatsächlich auch knifflig. Sehr umständlich. Manche Spalten mancher Tabellen müssen in ein exotischeres Format kopiert werden, und von diesem wieder zurück ins andere Format kopiert werden. Aber nicht alle, und nicht alle gleich. Ich würde die Finger davon lassen.

Es geht nämlich auch einfacher, jedenfalls für schlichte Wordpressbenutzer wie mich.

Deshalb hier meine schlichte Lösung für das Konvertieren einer Datenbank von ISO 8859-1 nach UTF-8:

  1. Eine zweite, leere Datenbank anlegen. In die kommt später die UTF-8-Version, die Original-DB lassen wir unangetastet.
  2. Die Originaldatenbank als SQL-Dump herunterladen.
  3. Der SQL-Dump ist eine – möglicherweise lange – Textdatei im ISO-Format. Das war ja unser Problem. Diese ISO-Datei mit einem geeigneten Textverarbeitungsprogramm öffnen und als Unicode-Datei speichern.
    – Das geht bei Windows einfach mit WordPad: “Speichern unter”, Format “Unicode-Textdokument”. Das wird dann übrigens wohl eine UTF-16-Datei, mit zwei Byte pro Zeichen. Vielleicht geht das auch mit Word oder Writer oder Notepad++. Eine Schwierigkeit ist allerdings, dass man nicht unbedingt sieht, was da wirklich im Text steht, da ein ü sinnvollerweise immer als ü gezeigt wird, egal ob es tatsächlich so aussieht: ü (UTF) oder so: ü (ISO). Wobei “tatsächlich” natürlich das falsche Wort ist.
  4. In der neu entstandenen Datei sollten jetzt alle Umlaute so komisch aussehen, nämlich durch zwei andere Zeichen repräsentiert – wenn ich die Datei nicht als Unicode-Datei betrachte.
  5. Diesen neuen SQL-Dump jetzt in die frische Datenbank hochladen. Zuvor mit Suchen/Ersetzen schauen, ob beim Anlegen der Tabellen in den SQL-Befehlen als Zeichensatz oder Kollation ISO/Latin 1 angegeben ist; das muss dann natürlich raus. (Hier gab es bei mir Schwierigkeiten. Erstens, weil die Datei recht groß ist. Zweitens, einfach so. Aber der Download mit phpMyAdmin und der Upload mit HeidiSQL danach hat geklappt.)
  6. Fertig. Die config.php mit den Zugangsdaten zur zweiten Datenbank versehen und schauen, ob das Blog mit der neuen Datenbank funktioniert. Dabei muss man Wordpress in den Einstellungen sagen, dass ab jetzt UTF-8 gilt und nicht mehr ISO. Dann – aber erst dann – kann man die ursprüngliche Datenbank löschen.

Das darf man alles bestimmt nicht. Und es führt zu grässlichen Datenbanken, Greueln im Auge des Herrn. Furchtbaren Hybriden oder so etwas. Ausprobieren auf eigene Gefahr, und ein paar SQL-Kenntnisse sind sicher hilfreich. Wer viel SQL kann, der wird sicher laut lachen und sagen, dass das alles doch viel einfacher geht.
Aber was soll ich sagen: bei mir funktioniert’s.

Anhang, nachträglich:
Mit einem Hex(adezimal)-Editor kann man sich anschauen, wie auf der Festplatte gespeicherte Dateien wirklich aussehen. (Na ja, wirklicher jedenfalls.) Hier zwei Textdateien in einem Hex-Editor dargestellt, die nur aus dem Text “Das ist ein Übel.” bestehen. Entschuldigung, ich wollte ein großes Ü drin haben.

Die obere Datei ist in Windows-1225 gespeichert, das ISO-8859-1 sehr ähnlich ist. Das Zeichen “D” ist durch die Zahl 44 kodiert, das Zeichen “a” durch “61″ (jeweils im Hexadezimalsystem). Pro Zeichen ein Byte. Der Editor ist so nett, rechts daneben gleich die gängige Entsprechung der Byte-Zahl anzuzeigen, so dass man nicht nur die tatsächlich gespeicherten Bytes sieht, sondern auch einen Hinweis darauf, wofür sie vermutlich stehen.
Die untere Datei ist in Unicode-16 gespeichert. Da sind für jedes Zeichen 2 Byte (16 bit) reserviert. Das Zeichen “D” bzw. der Unicode-Codepoint U+0044 ist durch die zwei Zahlen “44″ und “00″ repräsentiert. Warum zwei Bytes/Zahlen? Weil das bei UTF-16 immer so ist. Aber welche Zahl kommt zuerst, die 44 oder die 00? Im Prinzip geht beides, und es gibt auch beide Varianten – die eine heißt big-endian und die andere little-endian. Um sicher zu gehen, dass man weiß, welche Version benutzt wird, steht gerne mal am Anfang einer UTF-16-Datei “FFFE” beziehunsgweise eben “FEFF”. Und ja, big-endian und little-endian stammen aus Jonathan Swifts Gulliver’s Travels.

(In UTF-8 wäre das “D” nur durch die Ein-Byte-Zahl 44 kodiert, das “Ü” dagegen durch die zwei Bytes c3 und 9d. Und die obere Datei braucht nur halb so viel Speicherplatz wie die untere.)

6 Gedanken zu “ISO 8859-1, UTF-8 und Wordpress

  1. Auch wenn ich Haare spalte: Unicode umfasst 93 Schriftsysteme, nicht Alphabete. Denn die als CJK zusammengefassten chinesischen, japanischen (Kanji) und koreanischen Schriftzeichen (Hanja) sind kein Alphabete.

  2. Na, aber solche Haare lasse ich mir immer gerne spalten. Danke für die Berichtigung.

  3. DJH on 2.9.2011 at 17:28 sagte:

    Als kleine Ergänzung zum Exkurs: Der Browser weiß oft schon beim Empfangen der Daten, wie der Text kodiert ist – denn dafür gibt es den HTTP-Header „Content-Type“. Bei dir im Blog sagt er
    Content-Type: text/html; charset=UTF-8
    also bräuchtest du das Meta-Tag im HTML-Header eigentlich gar nicht mehr. In der Praxis kann man sich aber nicht immer darauf verlassen, dass der Content-Type-Header korrekt ist, selbst wenn man ihn z. B. mit PHP explizit setzen kann – das HTTP-Equiv(alent) im HTML funktioniert eben auch bei statischen HTML-Seiten, und unabhängig von der Server-Konfiguration (wird dann einfach überschrieben).

    Die Methode mag übrigens ein wenig mit dem Holzhammer kommen, mir fällt aber spontan auch keine bessere Lösung ein. Das Ergebnis zählt!

  4. Leider gibt es nicht nur ISO-8859-1 und ISO-8859-15 (das geringfügig andere mit dem €-Symbol) sondern auch noch Windows-1252. Dieser Zeichensatz ist an vielen Stellen der Tabelle deckungsgleich, aber eben doch nicht an allen. Viele Autoren (oder gar Programme?) deklarieren ISO-8859-1 und benutzen dann Windows-1252. Womöglich macht Rindernet Exploder keinen Unterschied bei der Anzeige, dann merken es die Leute beim Erstellen von Seiten gar nicht, wenn sie nur diesen benutzen.

    Übrigens gibt es einen gutes Argument dafür, diese Informationen nicht im Content-Type-Header sondern in einem Meta-Tag abzulegen: Sobald man HTML-Dateien abspeichert ist die Information verloren. Hier sieht man mal wieder, wie unzulänglich Dateisysteme sind: Sie können nur sehr wenige Meta-Informationen über Dokumente speichern. Das Encoding gehört nicht dazu, der Dateityp auch nicht.

  5. Stimmt, an HTTP hatte ich gar nicht gedacht. Zu gut kenne ich mich mit dem HTT-Protokoll nicht aus. (Im Informatikunterricht tippen die Schüler die Protokollzeilen per Hand ein und schicken eine GET-Anweisung an einen Webserver. Wenn die örtliche Firewall uns mal rauslässt.)

    Man macht sich halt wenig Gedanken darum, wie eine Text gespeichert wird. Gerade ausprobiert: der Windows-Notepad-Editor speichert in Windows-1252, da hat das Eurozeichen den Wert 80. (ISO-8859-15: A4.)

  6. KARL on 28.9.2011 at 9:39 sagte:

    Das ist richtig. ich kenne mich auch nicht mit HTTP aus, ich nutze immer einen Text – Editor, und füge dann meinen Text in meinen Homepage Baukasten ein. dann klicke ich auf HTML ansicht, und kopiere dann die Daten erneut in meine Webseite.

    so erhalte ich Layout,.. die h1 Formatierungen ,. und auch eine leerzeile wo eine Leerzeile hingehört,..

    gruß KARL

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Manchmal sollte man anderen das letzte Wort lassen, selbst wenn sie eine andere Meinung haben als man selber.

Post Navigation