Zeichensalat - Eine Einführung in Unicode

Im Zuge fortschreitender Internationalisierung und dem Zusammenwachsen von Märkten ist es wichtiger denn je internationalisierte Software zu schreiben. Angesichts von Japan, wo man 4 Schriften zugleich verwendet, fragt man sich natürlich, ob das nicht schon längst der Fall ist. Infos zu Unicode sind wichtig und werden hier vermittelt.

Einführung

Man vermutet, dass es auf der Erde ca. 4000-6000 Sprachen gibt und natürlich noch weit mehr Dialekte. Zwar haben nur die wenigsten von ihnen eine Schriftform der Sprache und viele mit Schriftform teilen sich wiederum die Schriftzeichen mit anderen Sprachen doch gibt es dennoch zehntausende Schriftzeichen. So manche Schrift, wie z. B. Keilschrift ist ausgestorben, wird aber dennoch weiter benötgt. Zu allem Überfluss gibt es auch noch verschiedene Schreibrichtungen. Theoretisch gibt es auf Papier acht Schreibrichtungen, praktisch werden aber nur vier davon genutzt (diejenigen, die links und rechts oben beginnen). Relativ eindrucksvoll ist das bei Japanisch. Dort gibt es im täglichen Schriftverkehr mindestens vier bzw. mit den arabischen Zahlen sogar fünf Schriften mit teils unterschiedlichen Schreiborientierungen. Ein Ansatz ist es, mehrere Zeichensätze und Codetabellen zu verwenden. Doch ist klar, dass bei Programm und Nationenübergreifender Arbeit dies keine praktikable Lösung ist. Aus diesem Grund wurde im Jahr 1991 das Unicode-Consortium ins Leben gerufen. Ziel war es einen einheitlichen Standard für internationale Textverarbeitung zu schaffen und mit dem Chaos hunderter Codepages und Dateikodierungen aufzuräumen.

Überblick

Bei Unicode handelt es sich um einen 1992 aus der Taufe gehobenen Interoperabilitätsnorm.

Hinter dieser Nrom stehen das Unicode Consortium und die ISO mit der Norm ISO/IEC 10646 - UCS. Ursprünglich haben beide an unabhängigen Norman gearbeitet. Doch war beiden recht schnell klar, dass das zwei universelle Zeichenkodierungen nicht das war, was die Welt braucht. Seit dem arbeiten beide eng zusammen und entwickeln ihre Normen parallel, so dass man sie als äquivalent bezeichnen kann. Heute gehören praktisch alle namhaften Softwareunternehmen dem Unicode Consortium an. Während der Entstehung dieses Textes war die Version 3.1 mit 94.140 Zeichen aktuell. Bei Unicode handelt es sich weit mehr als um eine Zeichentabelle. Es geht unter anderem um die Folgenden Aspekte:
*Kodeumfang
*Speicherung der Texte (Kodierung)
*Sortierreihenfolge
*Groß-/kleinschreibung
*Verschiedene Schreibrichtungen im gleichen Text
*Kombinierte Zeichen
*Äquivalenz von Zeichen
*Gespiegelte Zeichen (Klammer-Auf in LR- und RL- Schreibweise)
*Kompatiblilität und Umwandlung

Anforderungen

Dieses Kapitel soll sich mit den Anforderungen, die an eine Interoperabilitätsnorm für Textkodierung gestellt werden, auseinandersetzen. Hier werden Merkmale verschiedener Sprachen vorgestellt, die ein ensprechendes System folglich berücksichtigen muss.
Das griechische Alphabet und auch das davon abgeleitete lateinische Alphabet kennen Groß- und Kleinbuchstaben. Es haben also je zwei Zeichen eine besondere Beziehung zueinander (z.B. GROSSES-LATEINISCHES-H; KLEINES-LATEINISCHES-H). Programme benötigen oft eine Konvertierung zwischen großen und kleinen Buchstaben. Eine vollständige Unicode-Implementierung muss daher in der Lage sein dies zu Leisten. Sie benötigt folglich Wissen über die betroffenen Kodepunkte und ihre Beziehung.
Es existieren unterschiedliche Schreibrichtungen. Am bekanntesten ist wohl der Unterschied zwischen Lateintexten (links->rechts) und hebräischen Texten (rechts->links). Wenn dort Klammern gesetzt werden, dann enthält der Datenstrom die Ideen RUNDE-KLAMMER-AUF und RUNDE-KLAMMER-ZU. Je nach aktueller Schreibrichtung müssen die Klammern mal so und mal so gerendert werden. Der Renderer einer Unicodeimplementierung muss daher bei Spiegelbaren Zeichen die jeweils richtige Glyphe auswählen. Möchte man beide Sprachen in einem Text mischen, dann benötigt man auch Information über die Schreibrichtung. Es gibt daher Signale im Datenstrom, die die Schreibrichtung anzeigen. Auch dies muss ein Renderer beachten und passend handhaben. Sortierung, Klammern(Hierarchische Textebenen), Schreibrictungen, großklein umwandlung arabisch, das zeichen ineinanderschreibt. Hanguhl, das Zeichen mit kringeln versieht Diakritische Zeichen.


Dreiteilung
Das größte Verständnisproblem bei Unicode ist wohl, davon auszugehen, dass es den Unicode gibt. Es existiert es eine Dreiteilung: Zeichen, Zeichencode und Glyphe. Das Zeichen ist nur die Idee, nicht die Darstellung. Zum Beispiel die Idee des lateinischen großen A. Die Darstellung ist zunächst völlig unabhängig davon. Dieser Idee Lateinisches-Großes-A wurde durch das Unicodekonsortium eine Zahl zugeordnet. Z. B. 65. Die Zahlen unteligen dabei zunächst keiner Größenbeschränkung und sind mehr oder weniger willkührlich.
Im nächsten Schritt wird dann der Zahl eine grafische Repräsentation, eine Glyphe zugeordnet. Dies geschieht mit Schriften. In TrueType- / OpenType-Schriftdateien sind die grafischen Repräsentationen der Zeichen zusammen mit ihrer Zahl gespeichert. Da kaum eine Schrift alle Zeichen enthält, muss man Kompromisse machen. Das sieht dann so aus, dass man einen Textabschnitt mit dieser und einen anderen mit jener Schrift darstellt. Dabei kommt es vor, dass es für einige Zeichen keine Darstellung gibt. In solch eiem Fall sollte der Schriftrenderer dann eine Ersatzdarstellung verwenden. Das kann eine andere Schrift sein, oder ein spezielles oder generiertes Zeichen.


Umfang

Unicode ist ein ziemlich umfangreicher Standard. Es ist schon ein größeres Unterfangen eine vollständige Implementierung abzugeben. Zudem wächst der Standard ständig weiter. Auch eine Applikation muss das ihr Gebotene passend anwenden. Daher existieren verschiedene Implementierungslevel für Unicode:
Der Zeichenumfang von Unicode teilt sich auf in verschiedene Implementierungslevel.
Basic Encoding Scheme
Basic Multilingual Plane. Plane 0, abbreviated as BMP BMP Code Point. A Unicode code point between U+0000 and U+FFFF. (See
Block. A grouping
Supplementary Code Point. A Unicode code point between U+10000 and U+10FFFF.
Supplementary Character. A Unicode encoded character having a supplementary code point.
Surrogate Code Point. A Unicode code point in the range U+D800 through U+DFFF. Reserved for use by UTF-16, where a pair of surrogate code units (a high surrogate followed by a low surrogate) “stand in” for a supplementary code point.
Mirrored Property. The property of characters whose images are mirrored horizontally in text that is laid out from right to left (versus left to right)

Speicherung

Der vermutlich wichtigste Aspekt bei Unicode ist wohl die Speicherung der Texte und ihre interne Darstellung. Zu diesem Zweck hat definiert die Unicode-Norm drei verschiedene Kodierungsformen: UTF-32, UTF-16 und UTF-8, wobei UTF für Universal Character Set (UCS) Transformation Format (etwa: Universeller Zeichenmenge Umwandlungsformat - X) steht. Jede dieser Formen ist in der Lage die Zeichenkodes U+0000..U+D7FF darzustellen. Der Unterschied ligt in der verwendeten Mindestanzahl von Bytes, die für ein Zeichen benötigt werden. Wie die Namen bereits suggerieren sind es bei UTF-8 ein Byte, bei UTF-16 zwei und bei UTF-32 vier Bytes, die ein Zeichen mindestens belegt. Bei UTF-8 ist offensichtlich, dass die 55.295 Zeichen sich nicht mit einem Byte darstellen lassen. Es handelt sich bei UTF-8 daher um eine Kodierung, die die Zeichenkodes in 1 bis 6 Bytes hineinkodiert. Je nach Größe der Zahl.

Die ursprüngliche Unicode-Norm enthielt nur die Kodierungsform UTF-16, denn die zugrundeliegende Zeichenmenge UCS-2 passte bequem in die 65.536  Möglichkeiten hinein. Da UTF-16 jedoch nicht abwärtskompatibel zu ASCII ist und zu allem überfluss auch noch die Zeichenmenge kontinuierlich zunahm, kamen die Kodierungsformen UTF-8 und UTF-32 hinzu. Wegen seiner Abwärtskompatibilität bezüglich reinem ASCII-Text (U+00..U+7F) hat sich UTF-8 schnell als der bevorzugte Weg vieler Betriebsysteme und Programmiersprachen in Richtung Unicode herausgestellt. Denn UTF-8 arbeitet transparent mit 8-bittigen Zeichenketten.

UTF-32 ist mehr oder weniger eine Konseqzenz aus der Existenz von UFT-8 und UTF-16, jedoch ohne großartige Bedeutung. Ihr einziger Vorteil ist, dass hierbei ein linearer Zusammenhang zwischen Zeichenzahl und Länge des Datenstroms besteht. Immerhin setzen einige IBM-Systeme UTF-32 ein.
Neben der Kodierungsform unterscheidet man bei der Speocherung von Unicode noch zwischen verschiedenen Kodierungsschemen. Bei Prozessoren gibt es zwei Arten mehrbytige Zahlen darzustellen: Big Endian (Motorola) und Little Endian (Intel). Dies wirkt sich auf Dateiebene aus. Entsprechend gibt es bei UTF-16 und UTF-32 Probleme bei plattformübergreifendem Datenaustausch. Der Grund dafür ligt an der unterschiedlichen Anordnung der höher- und niederwertigen Bytes einer Zahl. Da der Algorithmus jedoch über die Plattformen gleich bleibt kommen unterschiedliche Resultate heraus. Daher unterscheidet man bei UTF-16 LE und BE sowie UTF-32 LE und BE. UTF-8 hat dieses Problem nicht, da es auf Basis einzelner Bytes arbeitet. Die Lösung dieses Problems ist das sogenannte Byte Order Mark (BOM). Dabei handelt es sich um das Zeichen U+FEFF am Dateianfang. Semantisch handelt es sich dabei um das Zeichen ZERO WIDTH NON-BREAKING SPACE. Anhand des gelesenen Werts kann eine Software entscheiden, wie die folgenden Werte zu interpretieren sind. Das BOM sollte nicht im Text vor kommen, wenngleich es nicht verboten ist. Statdessen sollte man das Zeichen
Bytes     Encoding Form
00 00 FE FF     UTF-32, big-endian
FF FE 00 00     UTF-32, little-endian
FE FF     UTF-16, big-endian
FF FE     UTF-16, little-endian
EF BB BF     UTF-8


U+E000..U+10FFFF
The use of U+2060 WORD JOINER is strongly preferred over ZWNBSP for expressing word joining semantics since it cannot be confused with a BOM.
UTF-8 darf auch BOM enthalten.


Byte Order Mark (BOM)

Ein BOM ist eine spezielle Zahl am Anfang einer Unicode-Datei. Die Kodierung der Datei darf dabei UTF-7, UTF-8, UTF-16 oder UDF-32 sein. Sie zeigt an, wie der Text einer Datei zu Interpretieren ist.



Bidi
Die Abkürzung Bidi steht für Bidirketional und trägt der Tatsache Rehnung, dass es in der Welt verschiedene Schreiborientierungen. Theoretisch exitieren 8 Schreiborientieungen. Praktisch werden jedoch nur drei benutzt: Links nach Rechts, Rechts nach Links und Oben nach Unten. Unicode enthält natürlich Unterstützung für gemischte Texte

Visual Order = sehenlesen, Logical Order = Schreiben, Phonetic Order
Mirrored attr


Darstellung
Contextual Variant. A text element can have a presentation form that depends on the textual context in which it is rendered. This presentation form is known as a contextual variant.


Sortierung


Zeichenmenge
Unicode ist ein gewachsener und weiterhin wachsender Standard. Es kommen also laufend neue Zeichen hinzu. Daneben garantiert Unicode aber Invarianz bezüglich alter Versionen. Aus diesem Grund unterscheidet man verschiedene Zeichenmengen, die eine Implementierung unterstützen kann: Die wohl wichtigste ist die Base MP??????????
UCS-2
BEM


Implementierungsgrad
Bei Unicode handelt es sich um eine durchaus umfangreiche Norm. Verständlich, wenn nicht jede Implementierung vollständig ist. Daher unterscheidet man bei Unicode verschiedene Implementierungsgrade. Hierbei seien insbesondere der schwierige Bereich der Sortierung aber auch BiDi genannt. Unicode definiert die folgenden Grade:???????????????? bei dem

Java/WinNT und Unicode
Windows NT und Java sind die Paradepferde der Unicode verwendenden Systeme. Sie stammen beide noch aus der Zeit als Unicode mit UTF-16 und UCS-2 gleichgesetzt wurde. Sie verwenden also beide 16-bit Zahlen zur Darstellung je eines Zeichens und sind somit auf die Basic Multilingual Plane (BMP,Plane 0) mit dem Bereich U+0000..U+FFFF festgelegt. Die Sublementary Planes können hiermit nicht dargestellt werden, denn sie erfordern bei UFT-16 zwei Datenwörter, Java und Windows NT sind jedoch auf Zeichen mit einem Datenwort fixiert.
Java und Unicode Java arbeitet mit StreamReader-n
C/C++ und Unicode Dateisysteme und Unicode FAT12/16/32 NTFS HPFS ext2, reiserFS, JFS XFS

OS/2, DOS, Win 3.x und Win 9x und Unicode

Das ist ein dunkles Kapitel und man verliert am Besten gar nicht viele Worte dazu

Windows NT ff. und Unicode Windows XP und Unicode Linux/*BSD und Unicode UTF-8

Andere sprachen und Unicode


Wissenswertes
So gibt es einen semantischen Unterschied zwischen dem lateinischen großen I und der römischen Ziffer I. Höhere römische Zahlen wie 4 sind sowohl im Unicode wie auch im Druck als Ligatur realisiert. Ebenso auch das spanische ll. Es sind zwar grundsätzlich zwei L und man darf es auch so schreiben. Im Satz handelt es sich jedoch wieder um eine Ligatur und es wird im Spanischen sogar als ein Buchstabe gehandhabt. Entsprechend gilt es bei der Sortierung als ein Buchstabe, wie vorgesehen
Q: What is a BOM?

A:  stream, where it can be used as a signature defining the byte order and encoding form, primarily of unmarked plaintext files. Under some higher level protocols, use of a BOM may be mandatory (or prohibited) in the Unicode data stream defined in that protocol. [AF]

Q: Where is a BOM useful?

A: A BOM is useful at the beginning of files that are typed as text, but for which it is not known whether they are in big or little endian format—it can also serve as a hint indicating that the file is in Unicode, as opposed to in a legacy encoding and furthermore, it act as a signature for the specific encoding form used . [MD] & [AF]

Q: What does ‘endian’ mean?

A: Data types longer than a byte can be stored in computer memory with the most significant byte (MSB) first or last. The former is called big-endian, the latter little-endian. When data are exchange in the same byte order as they were in the memory of the originating system, they may appear to be in the wrong byte order on the receiving system. In that situation, a BOM would look like 0xFFFE which is a noncharacter, allowing the receiving system to apply byte reversal before processing the data. UTF-8 is byte oriented and therefore does not have that issue. Nevertheless, an initial BOM might be useful to identify the datastream as UTF-8. [AF]

Q: When a BOM is used, is it only in 16-bit Unicode text?

A: No, a BOM can be used as a signature no matter how the Unicode text is transformed: UTF-16, UTF-8, UTF-7, etc. The exact bytes comprising the BOM will be whatever the Unicode character FEFF is converted into by that transformation format. In that form, the BOM serves to indicate both that it is a Unicode file, and which of the formats it is in. Examples:
Bytes     Encoding Form
00 00 FE FF     UTF-32, big-endian
FF FE 00 00     UTF-32, little-endian
FE FF     UTF-16, big-endian
FF FE     UTF-16, little-endian
EF BB BF     UTF-8

[MD]

Q: Can a UTF-8 data stream contain the BOM character (in UTF-8 form)? If yes, then can I still assume the remaining UTF-8 bytes are in big-endian order?

A: Yes, UTF-8 can contain a BOM. However, it makes no difference as to the endianness of the byte stream. UTF-8 always has the same byte order. An initial BOM is only used as a signature — an indication that an otherwise unmarked text file is in UTF-8. Note that some recipients of UTF-8 encoded data do not expect a BOM. Where UTF-8 is used transparently in 8-bit environments, the use of a BOM will interfere with any protocol or file format that expects specific ASCII characters at the beginning, such as the use of "#!" of at the beginning of Unix shell scripts. [AF] & [MD]


Do not tag every string in a database or set of fields with a BOM, since it wastes space and complicates string concatenation. Moreover, it also means two data fields may have precisely the same content, but not be binary-equal (where one is prefaced by a BOM). [MD]

Q: How I should deal with BOMs?

A: Here are some guidelines to follow:

   1.

      A particular protocol (e.g. Microsoft conventions for .txt files) may require use of the BOM on certain Unicode data streams, such as files. When you need to conform to such a protocol, use a BOM.
   2.

      Some protocols allow optional BOMs in the case of untagged text. In those cases,
          *

            Where a text data stream is known to be plain text, but of unknown encoding, BOM can be used as a signature. If there is no BOM, the encoding could be anything.
          *

            Where a text data stream is known to be plain Unicode text (but not which endian), then BOM can be used as a signature. If there is no BOM, the text should be interpreted as big-endian.
   3.

      Some byte oriented protocols expect ASCII characters at the beginning of a file. If UTF-8 is used with these protocols, use of the BOM as encoding form signature should be avoided.
   4.

      Where the precise type of the data stream is known (e.g. Unicode big-endian or Unicode little-endian), the BOM should not be used. In particular, whenever a data stream is declared to be UTF-16BE, UTF-16LE, UTF-32BE or UTF-32LE a BOM must not be used. [AF] & [MD]

 

It is very important to distinguish surrogate code points (in the range U+D800..U+DFFF) from supplementary code points (in the completely different range, U+10000..U+10FFFF). Surrogate code points are reserved for use, *in pairs*, in representing supplementary code points in UTF-16.





Surrogates

There is a need to support more characters than the 65,536 that fit in the 16-bit Unicode code space. For example, the Chinese speaking community alone uses over 55,000 characters. To answer this need, the Unicode Standard defines surrogates. A surrogate or surrogate pair is a pair of 16-bit Unicode code values that represent a single character. The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0.

Windows 2000 introduces support for basic input, output, and simple sorting of surrogates. However, not all system components are surrogate compatible. Also, surrogates are not supported in Windows 95/98/Me.

The system supports surrogates in the following ways:

General Guidelines for Software Development

Windows handles surrogates as pairs of 16-bit code values. The system processes surrogate pairs in a way similar to the way it processes nonspacing marks. At display time, the surrogate pair display as one glyph by means of Uniscribe. (This conforms to the requirements in the Unicode Standard, version 2.0)

Applications automatically support surrogates if they support Unicode and use system controls and standard APIs, such as ExtTextOut and DrawText. Thus, if your code uses standard system controls or uses general ExtTextOut-type calls to display, surrogate pairs should work without any changes necessary.

Applications implementing their own editing support by working out glyph positions for themselves may use Uniscribe for all text processing. Uniscribe has separate APIs to deal with complex script processing (such as line service, hit testing, and cursor movement). The application must call the Uniscribe APIs specifically to get these advanced features. Applications written to the Uniscribe API are fully multilingual. However, this does impose a performance penalty, so some applications may want to do their own surrogate processing.

Because surrogates are well defined, you can also write your own code to handle surrogate text processing. When a program encounters a separated Unicode value from either the lower reserved range or the upper reserved range, it must be one half of a surrogate pair. Thus, you can detect a surrogate pair by doing simple range checking. If you encounter a Unicode value in the lower or upper range, then you need to track backward or forward one 16-bit width to get the rest of the character. Keep in mind that CharNext and CharPrev move by 16-bit code points, not by surrogates.

For sorting, all surrogate pairs are treated as two Unicode code points. Surrogates are sorted after other Unicode code points, but before the PUA (private user area). Sorting for a standalone surrogate character (that is, either the high or low character is missing) is not supported.

If you are a font or IME provider, note that Windows disables surrogate support by default. If you provide a font and IME package that requires surrogate support, you must set the following registry values:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanguagePack] 
SURROGATE=(REG_DWORD)0x00000002

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\International\Scripts\42]
IEFixedFontName=[Surrogate Font Face Name]
IEPropFontName=[Surrogate Font Face Name]


Wird ein Zeichen in 4 Bytes codiert, so spricht man bei den ersten beiden vom high surrogate und bei den anderen vom low surrogate. High surrogates haben einen Wert zwischen D800 und DBFF, low surrogates zwischen DC00 und DFFF. Wird ein Zeichen in einer einzigen Code Unit kodiert, so dürfen diese Wertebereiche nicht als Code für ein einzelnes Zeichen verwendet werden, da sonst anhand einer Bytefolge nicht entschieden werden könnte, ob es sich um zwei einzelne Code Units oder um ein surrogate pair handel Q: What is the difference between UCS-2 and UTF-16? A: UCS-2 is what a Unicode implementation was up to Unicode 1.1, *before* surrogate code points and UTF-16 were added as concepts to Version 2.0 of the standard. This term should be now be avoided. When interpreting what people have meant by "UCS-2" in past usage, it is best thought of as not a data format, but as an indication that an implementation does not interpret any supplementary characters. In particular, for the purposes of data exchange, UCS-2 and UTF-16 are identical formats. Both are 16-bit, and have exactly the same code unit representation. The effective difference between UCS-2 and UTF-16 lies at a different level, when one is interpreting a sequence code units as code points or as characters. In that case, a UCS-2 implementation would not handle processing like character properties, codepoint boundaries, collation, etc. for supplementary characters. [MD] & [KW]