Zeichencodierung für’s Web – Was jeder wissen sollte!

25 Apr
25. April 2009

Gerade habe ich auf einen Artikel zur Zeichenkodierung bei JoelOnSoftware verwiesen und schon kommen die Bitten um eine deutsche Version herein. Natürlich kann ich da nicht wiederstehen.

Was muss ein webDesigner eigentlich wirklich über Zeichensätze wissen?

Falsche Zeichencodierung im Web

Falsche Zeichencodierung im Web

Die eine Gruppe der webDesigner übernimmt einfach den verlangten content-type Tag im HEAD-Bereich der HTML-Datei ohne ihn zu hinterfragen, die nächste versucht den Sinn zu erschliessen und die letzte ignoriert ihn einfach. Daher haben wir auch soviele Probleme mit der Darstellung von Zeichen im Web und in eMails. Ich habe einfach auf wordblog.de die ersten fünf Blogs aufgemacht und mal nachgeschaut und siehe da: Einer mit falscher Codierung war schon dabei.

Der richtige Umgang mit der Zeichencodierung ist gar nicht so schwer wie man vielleicht denkt!

Die seit jeher bekannte Weisheit “Plain Text = ASCII = 8 Bit per Zeichen” ist eine Legende. Es stimmt einfach nicht. Daher sollte jeder Programmierer und Desginer diesen Artikel einmal durchlesen, bevor er die nächste Zeile Code schreibt. Für alle die sich bereits eingehend mit “Internationalisierung” beschäftigt haben, kann dieser Artikel vielleicht ein wenig nach Binsenweisheiten aussehen, aber einige werden es trotzdem brauchen, damit Umlaute und Akzente wieder richtig ngezeigt werden.

1. Die Geschichte: ASCII und ANSI

darstellbare ASCII-Zeichen

darstellbare ASCII-Zeichen

Um diesen ganzen Kampf mit Zeichensätzen besser zu verstehen, ist es gut einen Blick auf die Geschichte zu werfen. Natürlich fange ich nicht bei der Keilschrift an und ignoriere auch EBCDIC, denn das berührt uns ganz und gar nicht. Damals in der Bronzezeit der IT wurde UNIX erfunden und mit der Programmierprache C war alles einfach. Denn mit ASCII wurde nur im englischen Alphabet geschrieben und es gab (anscheinend) keine nationalen Sonderzeichen. Mit ASCII wurden die Zeichen für die Arbeit am Computer mit Zahlen versehen, wobei die Zahlen 0 bis 31 für nicht-druckbare Zeichen (Steuerzeichen) reserviert sind und ab 32 die druckbaren Zeichen dargestellt sind. Bei den druckbaren Zeichen ist beispielsweise ASCII 32 das Leerzeichen, 65 das ‘A’, und 97 das ‘a’. Und bei den Steuerzeichen ist zum Beispiel ASCII 7 der Biep, 8 der Rückschritt und 10 der Zeilenvorschub. Zu dieser Zeit arbeiteten Computer mit Bytes zu je 8-Bit und die druckbaren Zeichen konnten ganz einfach mit 7-Bit gespeichert werden. Und so war die IT-Welt schön, wenn man nur Englisch brauchte.

Man hatte aber 8-Bit zur Verfügung und so wurde das “Reserve-Bit”, welches für die ASCII-Zeichen von 128 – 255 stand, bald für eigene Zwecke eingespannt. Leider waren nur die Zeichen 0 bis 127 genormt und alle möglichen Leute hatten die gleiche Idee, das 8. Bit für ihre Zwecke einzuspannen. So gab es die verschiedensten Zeichensätze zu dieser Zeit, bei dem einen war ASCII 185 ein ‘¹’, beim anderen ein ‘š’ und beim dritten war es gar nicht belegt. Dadurch hatte man das Problem, dass je nach Land und Computer verschiedene, wirre Ergebnisse zu Stande kamen. Ich kann mich noch gut an die Zeit erinnern, da Ungarn finnische Zeichensätze verwendeten und wenigsten ein paar nationale Sonderzeichen darstellen zu können.

Um ein wenig Ordnung in das Chaos zu bringen wurde der ANSI-Standard geschaffen. Gleich wie beim ASCII-Standard einigte man sich auf die unteren 128 Zeichen, welche international gleich waren. Aber zusätzlich legte man fest wie die Zeichen ab 128, abhängig vom Wohnort, belegt wurden. Dieses System nannte man in der Folge “Codepages”. Je nach Bedarf wurde die jeweilige Codepage unter DOS aktiviert, beispielsweise wurde für Englisch 437, für Mitteleuropa 850 und für kyrillisch 866 verwendet. Dies funktionierte in dem man Befehle in die Startdatei von DOS eintrug.

1
2
mode con codepage prepare=((850) C:\WINDOWS\COMMAND\ega.cpi)
mode con codepage select=850

Noch schwieriger war es im asiatischen Raum, da dort die Zeichensätze aus mehreren tausend Zeichen bestanden, welche niemals mit 8-Bit gespeichert werden konnten. Dort wurde mit einem “Double Byte Character Set” (DBCS) gearbeitet. Manche Zeichen wurden mit einem Byte dargestellt, andere wieder mit 2 Bytes. Für Programmierer war das Zusammenstellen eines Strings einfach, aber nahezu unmöglich diesen wieder zu zerlegen. Daher gab es in den Betriebssystemen, wie Windows, eigene Routinen, wie AnsiNext, um damit umgehen zu können.

All das klappte natürlich super, denn die Menschen wussten: 8 Bit = ein Byte = ein Zeichen. Aber es funktionierte nur, wenn man keine Daten zwischen den Computern austauschte und auch nur eine Sprache verwendete. Aber die Zeit schritt voran und das Internet wurde zum Massenmedium. Dadurch wurde es üblich Texte von einem Gerät zum nächsten zu senden und das Chaos war perfekt und ist es teilweise bis heute noch. Aber es gab schlaue Köpfe und Unicode wurde erfunden.

2. Die Gegenwart: Unicode

Unicode hat zum Ziel einen globalen Zeichensatz zu schaffen, welcher alle nur denkbaren Zeichen, die auf der guten alten Erde benötigt werden, enthält. Eine der größten Legenden ist, dass Unicode ein einfacher 16-Bit-Zeichensatz ist und daher 65.536 verschiedene Zeichen darstellen kann. In Wirklichkeit ist Unicode ein anderer Denkansatz um mit Zeichen umzugehen und diesen muss man verstehen, sonst macht der Rest keinen Sinn.

Bis jetzt dachten wir, dass der Buchstabe ‘A’ eine Entsprechung in ein paar Bits hat (A = 0100 0001 (dezimal: 65)) und irgendwo im Speicher oder auf der Festplatte abgelegt ist. In Unicode zeigt der Buchstabe ‘A’ auf einen Code Point. Dies ist noch immer ein theoretisches Konzept, wie es im Speicher oder auf der Festplatte abgelegt wird, ist eine andere Geschichte. In Unicode ist das ‘A’ ein rein platonische Idee. Das ‘A’ ist anders wie ein ‘B’ oder ein ‘a’, aber das gleiche wie ‘A‘, ‘A‘  oder ‘A‘. Die Idee dahinter ist, dass ein ‘A’ von jeder Schriftart unabhängig ein ‘A’ bleibt, also egal ob ich Helvetica, Arial oder Times einsetze und er ist auf jeden Fall unterschiedlich von einem “m”. Jetzt sagt ihr, dass ist ja klar und selbstverständlich! Aber so einfach ist es nicht, denn manchmal ist es schon sehr schwer zu bestimmen, was ein Buchstabe überhaupt ist. Denkt an das ‘ß’. Ist das jetzt ein eigener Buchstabe oder nur eine besondere Art ‘ss’ zu schreiben. Wir könnten jetzt auch diese Diskussion führen. Doch das Unicode-Konsortium hat das in den letzten Jahren für uns erledigt und genau diese Dinge genau festgelegt.

Jedes Zeichen in jedem Alphabet wurde durch das Unicode-Konsortium mit einer eindeutigen Nummer versehen, welche sich so schreibt: U+0047. Diese Zahl ist der Code Point und schlüsselt sich so auf: U+ bedeutet Unicode und die folgende Nummer ist eine hexadezimale Zahl. Das ‘A’ ist dabei U+0041 und U+0047 ist ein ‘G’. Jedes Betriebsystem hat ein kleines Tool integriert um sich diese Zeichen anzusehen oder man kann auch die Tabellen von der Unicode-Website herunterladen. Es wurde vom Konsortium nie eine Beschränkung auf 65.536 Zahlen festgelegt und in der Realität gibt es auch Zeichen mit einer größeren Ziffer. Damit kann auch nicht jedes Zeichen im Unicode-Format in eine 2-Byte-Struktur gequetscht werden. Aber das war ja so oder so nur eine Legende.

Nehmen wir an wir haben die Zeichenfolge ‘Guru 2.0‘. Diese entspricht in Unicode der Zahlenfolge: U+0047 U+0075 U+0072 U+0075 U+0020 U+0032 U+002E U+0030. Dies ist aber nur eine Abfolge von Code Points und wir haben noch nichts über die Art der Speicherung im Hauptspeicher oder auf einer Festplatte gesagt. Dies bring uns zum nächsten Kapitel.

3. Speichern der Zeichen: Encoding

Eine der ersten Ideen zum Encoding von Unicode war das Speichern der Nummern aus der Code-Point-Abfolge und dies führte auch zur 2-Byte Legende. Unser Text ‘Guru 2.0‘ wird dadurch zu: 00 47 00 75 00 72 00 75 00 20 00 32 00 2E 00 30. Rein technisch ist dies richtig, aber kann die Bytefolge nicht auch 47 00 75 00 72 00 75 00 20 00 32 00 2E 00 30 00 lauten? Ihr werdet sagen: Ja klar beides ist richtig. Das eine ist eine High-Endian und das andere ein Low-Endian, oder auch Big-Endian und Little-Endian, Schreibweise.

Jetzt hatten wir zwar ein funkelnagelneues System um Zeichen unabhängig zu codieren und auch schon wieder zwei Arten der Speicherung. So waren wir gezwungen am Anfang jedes Unicode Strings einen Marker, die sogenannte Byte-Order-Mark, für die Big-Endian ‘FE FF‘ oder für Littel-Endian ‘FF FE’ zu setzen. Ein Weile sah alles ganz gut aus, aber dann begann sich (amerikanische!) Programmierer zu beschweren: Es sind lauter 00-Marker vorhanden und die sind sinnlos, da wir ja nur bis Unicode 00 FF arbeiten. Auch gab es bereits genug Dokumente mit verschiedensten Arten von ANSI und DBCS-Codierungen. Und wer sollte diese Dokumente alle in Unicode konvertieren? Aus diesen Gründen wurde Unicode von den meisten Programmierern (wahrscheinlich englischsprechende) über die Jahre hinweg ignoriert und die Dinge wurden absolut nicht besser.

4. Eine brilliante Idee: UTF-8

Genau aus diesem Grund wurde UTF-8 erfunden. Dies war ein neues Systems um diese U+-Folgen, besser bekannt als Code Points, zu speichern. Für alle Codierungen unterhalb von 127 wird 1 Byte (also 8 Bit) verwendet und ab 128 werden zwei, drei oder bis zu 6 Bytes für die Speicherung verwendet.

An easy way to remember this transformation format is to note that the number of high-order 1’s in the first byte signifies the number of bytes in the multibyte character.
The UCS value is just the concatenation of the v bits in the multibyte encoding. When there are multiple ways to encode a value, for example UCS 0, only the shortest encoding is legal.

UTF-8 Byte-Sequenz aus 'UTF-8 History'

UTF-8 Byte-Sequenz aus 'UTF-8 History'

Ein ganz netter Nebeneffekt (Der war sicher beabsichtigt) war, dass englische Texte in UTF-8 und in ASCII genau gleich ausschauten.So bemerkten die Amerikaner keinen Unterschied (Anscheinend ist das wichtig, denn wir Europäer können mit soetwas sehr gut umgehen) und der Rest der Welt sprang durch den Feuerreifen.

Nehmen wir wieder unseren Text ‘Guru 2.0‘ und die Unicode-Folge U+0047 U+0075 U+0072 U+0075 U+0020 U+0032 U+002E U+0030. In UTF-8 sieht die Codierung dann so aus: 47 75 72 75 20 32 2E 30. Fällt euch etwas auf? Es gibt keinen Unterschied zur Codierung in ANSI, ASCII oder einem anderen OEM-Zeichensatz! Erst wenn wir Sonderzeichen wie Umlaute oder Akzente verwenden, müssen wir auf die Mehr-Byte-Methode ausweichen um die Code Points zu speichern, aber die Amerikaner werden es nicht bemerken.

5. Die Praxis: UTF-8 im Einsatz

Falls Du bis jetzt wieder alle Erklärungen vergessen hast, dann musst Du dir zumindest eines merken: Es gibt so etwas wie “reinen Text” nicht! Es ist sinnlos eine Zeichenfolge ohne der Codierung zu verarbeiten!

Sobald Di eine Textfolge hast und Du kennst die verwendete Codierung nicht, kannst Du ihn nicht mehr richtig anzeigen. Aussagen wie “Meine webSite hat so komische Zeichen!” oder “Ich kann das eMail nicht lesen, wenn Umlaute vorkommen!” sind alle darin begründet, dass irgendein ignoranter Programmierer die Codierung des Text nicht mitgeschickt hat. Es ist einfach: Wenn das Programm nicht weis ob es UTF-8, ASCII, Latin 1 (ISO 8859-1) oder Western European (Windows 1252) decodieren soll, zeigt es nur Müll an. Denn schätzen, ist bei der unendlichen Anzahl an Möglichkeiten einfach nicht drinnen.

Wie gibt man jetzt die Codierung mit? Bei einem eMail ist es einfach und standardisiert: Im Header muss die Zeile

Content-Type: text/plain; charset="UTF-8"

vorkommen. Bei einer webSeite war ursprünglich daran gedacht, dass der webServer die Codierung im http-Header mitsendet. Dies brachte aber Probleme. Gerade webServer welche tausende von Seiten in verschiedensten Sprachen anbieten, konnten nicht wirklich erkennen in welcher Codierung, welche Seite geschrieben wurde. Dadurch wurde auf einen HTML-Tag im HEAD-Bereich des Dokuments zurückgegriffen. Für Puristen ist dies natürlich ein Schreckgespenst. Denn wie soll man den Text lesen ohne die Codierung zu kennen. Und dies musste man, um die Codierung aus dem HEAD-Bereich herauszufiltern. Trotzdem klappt es, da in allen Codierungen die Zeichen bis 127 genormt sind, konnte man das HTML-Dokument soweit entziffern, bis der Codierungs-Marker gelesen und interpretiert wurde. Das ganze sieht dann so aus:

1
2
3
4
5
6
7
8
9
10
11
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"  dir="ltr" lang="de-DE">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    ...
  </head>
  <body>
    ...
  </body>
</html>

Der META-Tag muss aber wirklich der erste im HEAD-Bereich sein! Denn sobald der Browser auf den Tag trifft, beendet er das Parsen der Datei und beginnt nochmals von vorne mit der jetzt bekannten Codierung. Also wenn der Tag erst am Ende des HEAD-Bereichs auftritt wurden bereits alle css-Dateien und JavaScript-Dateien verarbeitet und müssen durch den Restart neu geladen und interpretiert werden.

Was passiert aber, wenn der Browser keinen Content-Type findet? Der Internet Explorer macht wiedermal etwas eigenartiges: Er versucht die Codierung zu schätzen. Das kann sogar klappen, da jede Sprache eine signifikante Abfolge an Buchstaben bei den einzelnen Wörtern hat. Weiters haben alte Codepages die nationalen Zeichen meistens in bestimmten Bereichen zwischen 128 und 255 abgelegt. Das funktionierte auch so gut, dass viele webDesigner (wahrscheinlich, jene die webSeiten einfach zusammenklickten) nicht auf die Idde kamen einen Content-Type in ihre HTML-Dateien einzufügen. Meistens schaute es ganz gut aus, bis sie etwas schrieben, dass der IE nicht interpretieren konnte und die ganze webSeite in japanisch anzeigte.

Zeichenkodierungsmenü im FireFox

Zeichenkodierungsmenü im FireFox

Was macht jetzt der geplagte Leser? Er benutzt das Menu “Ansicht > Zeichenkodierung” und spielt sich mit den verschiedensten Varianten herum, bis der Text ein wening klarer wird. Aber viele Anwender kennen das Menü gar nicht. Daher ist dies ein weiterer Grund den Content-Type immer (!!!) anzugeben.

6. Zeichenkodierung in der Datenbank: UTF-8

Das ganze wird dann schwierig, wenn auch noch eine Datenbank in’s Spiel kommt. Denn diese kann die Daten in den Textfeldern wieder in jeder beliebigen Codierung speichern. Auch hier ist es wichtig die Codierung anzugeben. Ich beziehe mich prinzipiell auf mySQL, aber es ist bei den anderen Systemen gleich bzw. ähnlich.

Kollation der mySQL-Datenbank festlegen

Kollation der mySQL-Datenbank festlegen

Zuerst muss man bei der Anlage der Datenbank festlegen in welcher Zeichencodierung die Daten generell gespeichert werden sollen. Üblicherweise nimmt man für die Kollation eine für den Zweck möglichst universelle Codierung, wie zum Beispiel UTF-8 (utf8_general_ci). Bei der Anlage der einzelnen Datenfelder in den Tabellen muss man auch wieder auf die Kollation achten. Diese wird aber by mySQL (phpMyAdmin) von der Basiseinstellung übernommen. Wenn man also alles “von Hand” erledigt ist dies kein Problem.

Verwendet man jedoch Install-Scripts wie bei WordPress und den PlugIns sollte man schon den SQL-Befehl überprüfen. Ansonsten hat man auf einmal verschiedene Codierungen in der Datenbank.

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE IF NOT EXISTS `blog_comments` (
  `comment_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `comment_post_ID` int(11) NOT NULL DEFAULT '0',
  `comment_author` tinytext NOT NULL,
  `comment_author_email` varchar(100) NOT NULL DEFAULT '',
  ...
  `comment_favicon_url` text NOT NULL,
  PRIMARY KEY (`comment_ID`),
  ...
  KEY `comment_date_gmt` (`comment_date_gmt`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=575 ;

Ganz am Ende findet man die Folge DEFAULT CHARSET=… dort wird die Zeichencodierung eingestellt und die sollte immer gleich wie die der Datenbank sein.

7. Fazit

  1. Es ist egal welche Codierung verwendet wird.
  2. Die verwendete Codierung immer angeben.
  3. Immer dieselbe Codierung für ein Projekt verwenden.
  4. In HTML-Seiten und in der Datenbank die gleiche Codierung verwenden.
  5. UTF-8 ist eine gute Wahl.

weiterführende Links:

Tags: , , , , , ,
17 Kommentare
  1. Ben says:

    Super Artikel! Vielen Dank! Nur leider ist Dein Layout in der Single-Ansicht der Artikel zerschossen und der Text dadurch fast nicht lesbar, weil er über die Sidebar läuft.

  2. ByteBros says:

    Danke für das Lob! Und danke für den Hinweis, habe das komplett übersehen.

  3. trokon says:

    Klasse Beitrag – räumt mit Mythen auf, richtige Tiefe, richtige Breite. Zur Empfehlung freigegeben ;-)

  4. Major Tom says:

    Sehr gut, schön langsam kapier ich es auch…
    Danke Guru!

  5. peter says:

    hi,
    Dein Punkt mit den ß und Unicode verstanden aber…
    das ß steht für sz “ess zett”, nicht ss, wird ja auch so ausgesproch. Es gibt auch ein großes ß …. SZ

  6. ByteBros says:

    hi,
    wieso schreibt man dann dass und nicht dasz statt daß?

  7. ByteBros says:

    Danke für den Hinweis. Auf Grund Deines eMails habe ich recherchiert und darauf die entsprechenden Massnahmen eingeleitet. Natürlich habe ich auch einen passenden Post geschrieben!

  8. Karin says:

    best explanation ever – Aber irgenwie weiß ich noch immer nicht wie ich einer .txt Seite die Kodierung mitgebe, wenn ich sie am Server ablege. :-((
    Website, E-Mai und DB war mir irgendwie bewusst, aber .txt finde ich nicht

  9. Karin says:

    Danke Guru 2.0.

    Mein Problem ist, ich verwende keinen Editor ich generierte das File mittels Script in meinem Contentmanagementsystem direkt in das Filesystem meines Servers. Wenn ich es in einem Editor aufmache und dort sage: anzeigen in UTF-8 sieht alles wunderbar aus. Wenn aber der IE oder der FF es anzeigen soll, dann sind die Osteuropäischen Zeichen z.B. in Namen nicht mehr in Ordnung.
    Daher fände ich spannend, welcher Zeichensatz für das File tatsächlich eingesetzt ist.

  10. Holger says:

    Hallo, kann mich nur anschliessen, ein sehr guter Artikel.

Kommentarfunktion deaktiviert.