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:
- The cmap 12 OpenType font format is introduced, which
directly supports the 4-byte character code. Refer to the OpenType font
specification for more detail.
- Windows USER supports surrogate-enabled IMEs.
- Windows GDI APIs support cmap 12 so surrogates can be displayed
correctly.
- Uniscribe APIs support surrogates.
- Windows controls, including Edit and Rich Edit, support
surrogates.
- HTML engine supports HTML page that includes surrogates for
display, editing (through Outlook Express), and forms submission.
- System sorting table supports surrogates.
- Planes
two and three (defined in ISO/IEC 10646) are reserved for ideographic
characters.These planes fall in the high surrogate range of U+D840 to
U+D8BF.
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]