4. Multibyte-Codesets

Der Abschnitt 3.5.2, „Vietnamesisch“ ließ schon erahnen, dass viele Schriften niemals mit den maximal 256 Zeichen, die der 8-Bit-Raum erlaubt, auskommen. Richtig haarig wird es bei den CJK-Sprachen Chinesisch, Japanisch und Koreanisch, die allesamt auf die chinesische Wortschrift, die sogenannten Hanzi (Kanji auf Japanisch, Hanja auf Koreanisch) zurückgehen. Wie der Name suggeriert, entstanden diese Ideogramme während der Han-Dynastie in China, und repräsentieren - im Gegensatz zur lateinischen Schrift - nicht die Lautung, sondern die Bedeutung, was z. B eine Japanerin in gewissem Maße in die Lage versetzt, auch chinesische Texte zu verstehen.

Chinesische Schriftzeichen und ihre in Japan und Korea verwendeten Derivate sind durchweg quadratisch und wurden ursprünglich von oben nach unten und rechts nach links gesetzt. Die heutige Praxis hat sich allerdings dem lateinischen Alphabet angepasst, es wird also von links nach rechts und oben nach unten geschrieben.

4.1. CJK-Sprachen

4.1.1. Chinesisch

In chinesischen Schulen differiert der Lehrplan für das erste Schuljahr daher signifikant von dem für deutsche Grundschulen vorgesehenen, was die Erschließung des Alphabets angeht. Etwas Ordnung in das Chaos kommt, wenn man in der Lage ist, die aus Grundwörtern gebildeten Kombinationen zu deuten: Wird das Ideogramm für die Sonne über dem Ideogramm für den Horizont angeordnet, entsteht das Schriftzeichen für „früh“, zwei ineinandergeschobene Bäume werden zum Wald, das gespiegelte Schriftzeichen für einen Beamten bedeutet Fürst.

Weder die im Jahre 1892 eingeführte chinesische Lautschrift (im Gegensatz zur von der Aussprache unabhängigen Wortschrift), noch die im Jahre 1926 versuchsweise eingeführte, auf lateinischen Buchstaben aufbauende Lautschrift vermochten sich durchzusetzen. Die chinesische KP ließ die Schriftzeichen zwar vereinfachen, hielt aber an der Wortschrift fest, um eine sprachliche Zersplitterung der Volksrepublik China zu vermeiden.

4.1.2. Japanisch

Die chinesische Schrift wurde vor ca. 2400 Jahren in Japan eingeführt. Als agglutinierende Sprache entzieht sich das Japanische jedoch einer adäquaten Darstellung mit chinesischen Ideogrammen. Daher wurden ca. 250 zusätzliche Kanji mit rein phonetischer Funktion, die sogenannten Kana eingeführt, die etwa im 9. Jahrhundert zu den noch heute gebräuchlichen Katakana weiterentwickelt wurde. Ungefähr zur gleichen Zeit entstanden aus häufig auftretenden Zeichenkombinationen die Hiragana, die zur Wiedergabe japanischer Silben dienten. Heute ist die japanische Schrift eine Mischschrift aus ca. 1850 Kanji, den Hiragana und den z. B. für Fremdwörter benutzten Katakana.

4.1.3. Koreanisch

Das Koreanische ist entfernt mit dem Japanischen verwandt, und bedient sich einer Silbenschrift, die durch wiederholte Vereinfachungen aus der chinesischen Schrift hervorgegangen ist.

4.2. Escaping

Angesichts der Vielzahl der darzustellenden Schriftzeichen erscheint die Idee, die ideographischen CJK-Schriften im 8-Bit-Raum darzustellen, natürlich völlig absurd. Scheinbar reicht ein Byte mit acht Bit also spätestens in Ostasien nicht mehr zur Darstellung eines Schriftzeichens aus. Man könnte natürlich einfach mehr Bits in ein Byte packen, um einen größeren Zahlenraum zu schaffen, oder die Eins-Zu-Eins-Beziehung zwischen Bytes und Schriftzeichen aufgeben. Allerdings ist genau diese Eins-Zu-Eins-Beziehung so stark in allen Computer-Betriebssystemen verwurzelt, dass eine generelle Änderung zu enormen Schwierigkeiten führen würde.

Im Abschnitt 2.2, „Von Bits und Bytes“ wurde ja schon beschrieben, wie man es trotz 8-Bit-Bytes hinbekommt, einen Computer mit Zahlen, die weitaus größer als 256 sind, rechnen zu lassen. Man muss lediglich mehrere Bytes (2, 4, 8, ...) zu logischen Einheiten zusammenfassen. Aber auch dieser Ansatz führt zu Schwierigkeiten: Wird ASCII-Text (oder auch Text mit beliebigen 8-Bit-Zeichen) von einem „neuen“ auf ein „altes“ System übertragen, kommt auf dem alten System ein Datenstrom an, der jeweils abwechselnd aus dem Zeichen mit der Nummer Null und dem eigentlichen Zeichen aufgebaut ist. Das Zeichen mit der Nummer Null hat allerdings auf praktisch allen Betriebssystemen, eine Sonderbedeutung, die der Programmiersprache C entstammt: Das sogenannte Null-Byte kennzeichnet das Ende einer Zeichenkette. Programme hören beim ersten Null-Byte also einfach auf, einen Text zu lesen.

Wir werden später sehen, dass dieser Ansatz trotzdem verfolgt wird, er hat aber seine spezifischen Schwierigkeiten. Es gibt aber eine weitere Möglichkeit, die 256-Zeichen-Grenze auch mit 8-Bit-Zeichen zu durchbrechen, das Escaping.

Nehmen wir an, wir hätten die Aufgabe nur mit den Buchstaben des lateinischen Alphabets die deutschen Umlaute Ä, Ö, Ü, ä, ö und ü sowie das ß darzustellen. Jeder kennt den Trick, man schreibt ae, oe, ue und ss, in Computer-Lingo: Wir kodieren bestimmte deutsche Schriftzeichen mit 2 Bytes. Nicht nur für Computer ist diese Codierung aber eigentlich unbrauchbar, denn wir können jetzt nicht mehr zwischen der zuweilen vorkommenden Buchstabenkombination ae und einem ä unterscheiden. Das Wort „Masse“ wäre nur noch aus dem Zusammenhang deutbar, denn es kann sowohl für die echte Masse, als auch für Maße stehen.

Es ist aber auch eine eindeutige Codierung möglich: In der deutschen Sprache taucht der Buchstabe q nur in der Kombination qu auf. Jedes andere Vorkommen eines q ist „illegal“. Eine „kugelsichere“ Codierung könnte also so aussehen: Ein ä wird als „qa“ codiert, ein Ä als „QA“, ö entsprechend als „qo“ und ü/Ü als „qy/QY“ (um die legale Kombination qu zu vermeiden). Aus dem Eszet könnte schließlich ein „qs“ werden, nicht sehr gut lesbar, aber eindeutig.

Nachteil dieser Methode wäre, dass wir keine Wörter aus anderen Sprachen darstellen können, die unsere Restriktion für die Verwendung des q nicht kennen. Das lässt sich aber leicht ausbügeln, indem man die Konvention erweitert: Ein „echtes“ q wird als „qq“ bzw. „QQ“ dargestellt.

Wenden wir die vollständige Regel auf den letzten Absatz an, würden wir folgendes sehen:

Nachteil dieser Methode wqare, dass wir keine Wqorter aus anderen Sprachen darstellen kqonnen, die unsere Restriktion fqyr die Verwendung des qq nicht kennen. Das lqasst sich aber leicht ausbqygeln, indem man die Konvention erweitert: Ein „echtes“ qq wird als „qqqq“ bzw. „QQQQ“ dargestellt.

Lediglich die Darstellung der längeren „Q-Folgen“ erscheint etwas holprig. Ansonsten bleibt der Text aber durchaus lesbar, und selbst jemand, der unsere Konvention nicht kennt, wird das System spätestens beim zweiten Lesen verstanden haben.

Verallgemeinert lässt sich die Methode also so beschreiben: Man wählt ein (oder auch zwei) Escape-Zeichen aus, vorzugsweise eines, das in normalen Daten selten anzutreffen ist, legt eine Regel fest, dass die auf das Escape-Zeichen folgenden Zeichen eine Sonderbedeutung haben, und sorgt dafür, dass man das Escape-Zeichen noch immer darstellen kann, indem man es z. B. durch sich selber escapen lässt.

Der Trick ist ziemlich alt. In alten Drucker-Handbüchern findet man seitenweise solche Escape-Sequenzen. Wenn formatierte Textdateien ausgedruckt werden, müssen die Format-Informationen (Zeichensatz, fett, kursiv, unterstrichen, ...) ja irgendwie an den Drucker übermittelt werden. Traditionell schickte man dafür das Zeichen mit der Nummer 27 (im Bereich 0-31 für Control-Chars), gefolgt von Zeichenkombinationen, die eben im Druckerhandbuch dokumentiert waren. Dort konnte z. B. stehen, dass mit der Zeichenkombination „Zeichen Nummer 27 gefolgt von [31m“ die Schriftfarbe auf Rot gesetzt wird (bei Terminals ist das meistens sogar so: echo -e "\033[31m").

Weil das Zeichen mit der Nummer 27 so gerne für diesen Zweck eingesetzt wird, heißt es auch Escape und liegt auf der Taste Esc. Man kann die Idee aber auch noch weiterführen, und neben dem Escape-Zeichen auch noch ein Zeichen definieren, das eindeutig das Ende der Escape-Sequenz kennzeichnet. Nimmt man als Escape-Zeichen das kaufmännische Und und als Ende-Markierung das Semikolon, hat man die HTML-Autoren geläufige XML-Entity-Darstellung, bei der ein ä zu &auml; wird, und (weil das Escape-Zeichen selber immer auch in das Escaping einbezogen werden muss) zwingendermaßen die Folge &amp; für das eigentliche Kaufmanns-Und. Verwendet man als Escape-Zeichen „Kleiner-Als <“ und als Ende-Markierung „Größer-Als >“ hat man einen weiteren Weg gefunden, wie man beliebige Zusatzinformationen in einem Text unterbringen kann. Letztere Technik wird in SGML und daraus abgeleiteten Markup-Sprache wie HTML oder XML angewandt.

4.3. Multi-Byte-Encodings

Praktisch alle Kodierungen für Zeichen außerhalb des 7-Bit-Raums von ASCII bzw. des 8-Bit-Raums von Single-Byte-Codesets beruhen auf diesem Trick. Immer werden bestimmte Zeichenfolgen für die Erweiterung „missbraucht“, und die darauffolgenden Zeichen werden in einem anderen Kontext interpretiert. Der Standard ISO 8859 sieht z. B. einen Mechanismus vor, wie man durch Escape-Sequenzen aus dem 7-Bit-ASCII-Raum auf die obere Hälfte des Codesets (das die Sonderzeichen enthält) um- und wieder zurückschalten kann. Dieser Vorgang wird auch Shiften genannt.

Die meisten Kodierungen für ideographische Schriften mit mehr als 255 Zeichen gehen ähnlich vor. Gängig ist eine Definition, in der alle ASCII-Zeichen für sich selber stehen, und alle 8-Bit-Zeichen (also in ISO-8859-1 die obere Hälfte) eine Multi-Byte-Sequenz einleiten. Eine fiktive Codierung sähe so aus: Die Zeichen 0-127 entsprechen exakt ASCII und werden as is transparent durchgereicht. Hat ein Byte einen Wert im Bereich 128 bis 255 wird ein weiteres Byte gelesen und der Zahlenwert beider Bytes multipliziert.

Wieviele Zeichen könnten wir damit darstellen. 128 Zeichen (0-128) sind schon in ASCII definiert. Das erste Multi-Byte-Zeichen ist Nummer 128. Wenn es von einem Null-Byte gefolgt ist, ergäbe sich nach der obigen Regel 128 x 0 = 0, also exakt ein Null-Byte. Folgt auf ein Byte mit dem Wert 128 eins mit dem Wert 25, wird damit Zeichen Nummer 3200 erzeugt. Maximal könnten zwei Bytes mit dem Wert 256 aufeinanderfolgen. Hier würde sich der Code aus (256 - 128) x 256 = 128,

Das Verfahren wäre einfach, hätte aber etliche Nachteile (in der Praxis geht man schlauer vor). Zunächst einmal ist die Codierung nicht eindeutig, ein und dasselbe Zeichen ließe sich auf mehrfache Art und Weise darstellen. Das erscheint auf den ersten Blick harmlos, wenn es aber darum geht, einen Text nach einer bestimmten Zeichenfolge zu durchsuchen, müsste nach sämtliche Bytefolgen gesucht werden, die für diese Zeichenfolge möglich sind. Das ist ein ziemlicher Nachteil.

Ein weiteres Problem ist die fehlende Segregation der Codierung. Stoßen wir in einem Datenstrom beispielsweise auf ein Byte mit dem Wert 65, lässt sich nicht festellen, ob es dem (ASCII-)Zeichen A entspricht, oder Teil einer Multi-Byte-Sequenz ist. Dieser Mangel ließe sich beheben, indem man fordert, dass auch das zweite Byte im Bereich 128-255 liegen muss. Dann könnte man bei jedem Byte an seinem Wert erkennen, ob es Teil einer Mulit-Byte-Sequenz ist, oder aber ein ASCII-Zeichen.

Weiterhin fehlt es an einer Synchronisation. Gesetzt den Fall, wir hätten die fehlende Segregation wie beschrieben behoben, lägen alle in Multi-Byte-Sequenzen erlaubten Bytes im Bereich 128-255. Wollen wir allerdings bei einem solchen Byte feststellen, wo der Anfang, und das Ende des Multi-Byte-Zeichens ist, stehen wir auf dem Schlauch. Wir müssen von Anfang an nachzählen. Beispiel:

Am Anfang ASCII, aber dann ÄÖéä§ßßüÖÖüßß§°µäü und weiter im Text

Was ist jetzt ein Zwei-Byte-Zeichen? Die Kombination aus Grad und My, oder My und ä? In der Praxis ist das wichtig, denn dort kommen solche Situationen, in denen man einen Bytestrom verarbeiten muss (und nicht an den Anfang zurückkehren kann, um nachzuzählen) häufig vor.

Die Codierung hat aber auch einen Vorteil: ASCII-Zeichen werden transparent durchgereicht. Das ist einerseits für die Lesbarkeit wichtig, wenn ein Text vergleichsweise wenig Sonderzeichen (im Verhältnis zu ASCII) enthält. Liest man auf einer schlecht konfigurierten Web-Site das Wort „¤rchen“ (das Beispiel ist UTF-8, das fälschlicherweise als ISO-8859-1 interpretiert wird), kann man trotzdem noch erkennen, dass von einem Märchen und nicht einem Mädchen die Rede ist. Noch wichtiger wird die ASCII-Transparenz, wenn Texte von Maschinen und nicht von Menschen interpretiert wird. Maschinen/Programme springen meist auf bestimmte Schlüsselwörter an, und sehr häufig sind diese Schlüsselwörter auf die Verwendung von ASCII-Zeichen beschränkt. Werden ASCII-Zeichen von der Codierung nicht angetastet, funktionieren diese Programme weiterhin. Weitergedacht ist dies auch ein starkes Argument für die Forderung, dass Multi-Byte-Codes grundsätzlich keine ASCII-Zeichen enthalten sollten, um eine zufällige Fehlinterpretation auszuschließen.

Beherzigen wir diesen Ratschlag bei unserer Codierung, fordern wir also, dass das zweite Byte unserer Multi-Byte-Sequenzen ebenfalls immer aus dem Bereich 128-255 stammen muss (damit „opfern“ wir natürlich die Hälfte des theoretisch möglichen Wertebereichs), ist unsere Codierung auch file-system-safe. Was verbirgt sich dahinter? Hätten wir definiert, dass beispielsweise die Kombination „ä/“ für ein japanisches Hiragana stehen soll, könnten wir die Codierung nicht für die Benennung von Dateien verwenden, denn unser Dateisystem kennt unsere Codierung höchstwahrscheinlich nicht, und wird sich am Slash (/) im Dateinamen stören.

4.4. Bekannte Multi-Byte-Encodings

Gerade für den asiatischen Raum werden bereits seit langem Multi-Byte-Encodings verwendet. Diese Codierungen sind meist erheblich intelligenter als die oben beschriebene Ad-Hoc-Idee, und sind auch in Unicode-Zeiten noch sehr verbreitet. Die perfekte Codierung gibt es nicht, und so wundert es nicht, dass etliche zueinander inkompatible Kodierungen in Gebrauch sind.

Noch nicht einmal offiziell standardisiert, trotzdem weit verbreitet ist beispielsweise Big5, meist als traditionelles Chinesisch bezeichnet. Vereinfachtes (simplified) Chinesisch ist unter dem Namen GB2312 bekannt. Für Koreanisch ist eine Codierung unter dem Namen JOHAB verbreitet, für Japanisch wird oft das von Microsoft entworfene Shift-JIS verwendet.

Die sehr alten EUC-Codierungen existieren in Variationen für verschiedene Länder/Sprachen unter den Namen EUC-JP, EUC-CN, EUC-TW, EUC-KR.

Perfekt wird das Chaos dadurch gemacht, dass für fast alle Codierungen noch etliche Alias-Namen definiert sind, EUC-CN, CN-GB, csGB2312, EUCCN, EUC_CN, GB2312 bezeichnen alle ein und das selbe Codeset.

Und noch eine schlechte Nachricht: Imperia ist unicode-fähig, die oben beschriebenen Multi-Byte-Codesets sind aber eben nicht Unicode. Zur Zeit (April 2003) ist Imperia nicht in der Lage, diese Codesets korrekt zu verarbeiten (genauer gesagt: Imperia ist nicht in der Lage, zwischen solchen Codesest zu konvertieren). Um alle Imperia-Features für ostasiatische Sprachen auszunutzen, muss zur Zeit Unicode verwendet werden. Allerdings existieren etliche Tools, die Unicode in jedes noch so exotische Codeset konvertieren, so dass diese Einschränkung in der Praxis wenig Relevanz besitzt.