Normalisierung (Unicode)
Der Unicode-Standard kennt unterschiedliche Normalformen von Unicode-Zeichenketten und Algorithmen zur Normalisierung, also zur Überführung einer Zeichenkette in eine solche Normalform.
Für viele Zeichen gibt es mehrere Möglichkeiten, sie als Kette von Unicode-Zeichen darzustellen (z. B. das „ö“ als solches oder als „o“ mit Trema). Ein einfacher Byte-Vergleich genügt daher nicht, denn er könnte Unterschiede in der Codierung erkennen, die aber keine Unterschiede im Text bedeuten. Um festzustellen, ob zwei Zeichenketten den gleichen Text repräsentieren, ist es daher hilfreich, beide in die gleiche Normalform zu überführen.
Normalformen
Es gibt vier Normalformen:
- NFD: die kanonische Dekomposition
- NFC: die kanonische Dekomposition, gefolgt von einer kanonischen Komposition
- NFKD: die kompatible Dekomposition
- NFKC: die kompatible Dekomposition, gefolgt von einer kanonischen Komposition.
kanonische Äquivalenz | kompatible Äquivalenz | |
---|---|---|
zerlegt | NFD | NFKD |
kombiniert | NFC | NFKC |
- In den zerlegten Formen NFD und NFKD werden alle Zeichen, die sich auch mit Hilfe kombinierender Zeichen darstellen lassen, zerlegt.
- In den zusammengesetzten Formen NFC und NFKC wird ein einzelnes Zeichen für eine Folge aus Grundzeichen und kombinierenden Zeichen gewählt, falls dies möglich ist.
Kanonische Äquivalenz
Wenn zwei Zeichenketten kanonisch äquivalent sind, dann stellen sie exakt den gleichen Inhalt dar, nur sind eventuell andere Folgen von Unicode-Zeichen gewählt. Dass es mehrere Darstellungen gibt, hat mehrere Gründe:
- Für viele Buchstaben mit diakritischen Zeichen definiert der Unicode-Standard ein eigenes Zeichen. Solche Zeichen lassen sich aber auch darstellen als der Grundbuchstabe, gefolgt von einem kombinierenden diakritischen Zeichen.
Beispiel: Der Buchstabe Ä existiert als eigenes Zeichen U+00C4, kann aber auch als Folge U+0041 U+0308 kodiert werden. - Folgen auf ein Zeichen verschiedene kombinierende Zeichen, die an unterschiedlichen Stellen des Grundbuchstabens stehen, so spielt ihre Reihenfolge für die Darstellung keine Rolle.
SowohlU+0061 U+0308 U+0320
als auchU+0061 U+0320 U+0308
ergeben ä̠, währendU+0061 U+0308 U+0304
ǟ ergibt undU+0061 U+0304 U+0308
dagegen ā̈. - Manche Zeichen sind doppelt im Standard enthalten, etwa Å, das sowohl an der Position U+00C5 als „Lateinischer Großbuchstabe A mit Ring“ kodiert ist als auch an der Stelle U+212B als „Ångströmzeichen“.
Kompatible Äquivalenz
Sind zwei Zeichenketten nur kompatibel äquivalent, so stellen sie zwar den gleichen Inhalt dar, allerdings kann die Darstellung leicht unterschiedlich sein. Folgende Abweichungen können vorkommen:
- Hoch-/Tiefgestellte Zeichen: Die hochgestellte Ziffer 2 (², U+00B2) ist eine Kompatibilitätsvariante der Ziffer 2, ebenso die tiefgestellte (₂, U+2082).
- Andere Schriftart: Der Großbuchstabe Z mit Doppelstrich (ℤ, U+2124) entspricht dem gewöhnlichen Z, nur liegt er in einer anderen Schriftart vor.
- Initiale/mediale/finale/isolierte Form eines Zeichens: Obwohl für Arabisch in Unicode nur ein Zeichen für jeden Buchstaben vorgesehen ist, auch wenn er je nach Stellung eine andere Form hat, sind dennoch auch diese einzelnen Formen als eigene Zeichen kodiert. Diese Zeichen sind als entsprechende Kompatibilitätsvarianten des im Unicode-Standard bevorzugten Zeichens gekennzeichnet.
- Ohne Umbruch: Einige Zeichen unterscheiden sich nur bei Anwendung des Unicode-Zeilenumbruch-Algorithmus voneinander, so ist das geschützte Leerzeichen nur ein Leerzeichen, das keinen Umbruch zulässt.
- Eingekreist: Der Unicodeblock Umschlossene alphanumerische Zeichen und weitere Blöcke enthalten viele eingekreiste Zeichen, etwa die eingekreiste Ziffer 1 (①, U+2460), die eine Variante der gewöhnlichen 1 ist.
- Bruch: Brüche wie etwa ½ (U+00BD) können auch mit Hilfe des Bruchstrichs (U+2044) geschrieben werden.
- andere Breite oder Ausrichtung, quadratisch: Die ostasiatische Typographie kennt Zeichen in unterschiedlichen Breiten und solche, die im vertikalen Layout um 90° gedreht gegenüber der üblichen Darstellung erscheinen.
- Sonstiges: Einige Normalisierungen fallen in keine dieser Kategorien, darunter die Auflösung von Ligaturen.
Normalisierung
Die Überführung einer Zeichenkette in eine der vier Normalformen nennt man Normalisierung. Um diese durchzuführen, definiert der Unicode-Standard mehrere Eigenschaften:
Decomposition_Mapping
gibt zu jedem Zeichen an, in welche Zeichenfolge es zerlegt werden kann, falls dies möglich ist. Die Eigenschaft nennt sowohl die kanonischen als auch die kompatiblen Zerlegungen.Decomposition_Type
gibt an, ob es sich bei der Zerlegung um eine kanonische oder eine kompatible Zerlegung handelt. Im letzteren Fall wird auch angegeben, welcher Art diese ist.Canonical_Combining_Class
(kurzccc
) ist eine Zahl zwischen 0 und 254, die für kombinierende Zeichen in etwa angibt, an welcher Stelle des Grundzeichens sie stehen. Haben zwei kombinierende Zeichen unterschiedliche Werte, so interagieren sie grafisch nicht miteinander und können vertauscht werden, ohne dass sich die Darstellung ändert.- Ein Zeichen besitzt die
Full_Composition_Exclusion
-Eigenschaft, falls es zwar eine kanonische Zerlegung besitzt, aber in den zusammengesetzten Normalformen dennoch nicht verwendet werden soll. Hangul_Syllable_Type
wird bei für die Zerlegung koreanischer Silbenblöcke verwendet.
Algorithmus
Zur Überführung in eine der Normalformen führt man folgende Schritte durch:
Im ersten Schritt wird die Zeichenkette vollständig zerlegt: Zu jedem Zeichen wird ermittelt, ob eine Zerlegung existiert, und es wird gegebenenfalls durch diese ersetzt. Dieser Schritt ist wiederholt auszuführen, da die Zeichen, in die ein Zeichen zerlegt werden, selbst wieder zerlegbar sein können.
Für die kanonischen Normalformen werden nur kanonische Zerlegungen verwendet, bei kompatiblen Normalisierungen sowohl die kanonischen als auch die kompatiblen. Die Zerlegung koreanischer Silbenblöcke in einzelne Jamo wird dabei von einem gesonderten Algorithmus durchgeführt.
Anschließend werden die kombinierenden Zeichen, die zu dem gleichen Grundzeichen gehören, wie folgt sortiert: Folgen zwei Zeichen A und B aufeinander, für die gilt ccc(A) > ccc
(B) und ccc(B) > 0
, so werden diese beiden Zeichen vertauscht. Dieser Schritt wird so lange wiederholt, bis es keine benachbarten Zeichenpaare mehr gibt, die vertauscht werden können.
Für die zusammengesetzten Normalformen folgt ein dritter Schritt, die kanonische Komposition: Dazu wird (beginnend mit dem zweiten Zeichen) für jedes Zeichen C geprüft, ob ein vorhergehendes Zeichen L folgende Eigenschaften besitzt:
ccc
(L) = 0- Für alle Zeichen A zwischen L und C gilt 0 <
ccc
(A) <ccc
(C) - Es gibt ein Unicode-Zeichen P, das nicht als
Full_Composition_Exclusion
gekennzeichnet ist und die kanonische Zerlegung <L, C> besitzt.
In diesem Fall wird L durch P ersetzt und C entfernt.
Um aus Folgen von Jamo wieder Silbenblöcke mit eigenen Unicode-Codepunkten zu erhalten, wird der Algorithmus zur Zerlegung der Silbenblöcke umgekehrt angewendet.
Eigenschaften
Text, der nur aus ASCII-Zeichen besteht, ist schon in jeder der Normalformen, Text aus Latin-1-Zeichen in NFC.
Die Verkettung zweier Zeichenketten in Normalform ist manchmal nicht in Normalform, ebenso kann ein Austausch von Klein- und Großbuchstabe die Normalform zerstören.
Alle Normalisierungen sind idempotent, wendet man sie also ein zweites Mal an, so bleibt die Zeichenkette wie sie ist. Jede Abfolge von Normalisierungen kann durch eine einzige Normalisierung ersetzt werden; das Ergebnis ist eine kompatible Normalisierung, falls eine der beteiligten Normalisierungen kompatibel ist, sonst eine kanonische.
Der Unicode-Standard stellt einige Eigenschaften zur Verfügung, dank denen effizient getestet werden kann, ob eine gegebene Zeichenkette in Normalform vorliegt oder nicht.
Stabilität
Zum Zwecke der Abwärtskompatibilität wird garantiert, dass eine Zeichenkette, die in einer Normalform vorliegt, auch in künftigen Versionen des Unicode-Standards in Normalform vorliegen wird, sofern sie keine bisher nicht zugewiesenen Zeichen enthält.[1]
Ab der Version 4.1 wird zusätzlich garantiert, dass sich auch die Normalisierung selbst nicht ändert. Davor hatte es einige Korrekturen gegeben, die dazu führten, dass manche Zeichenketten in unterschiedlichen Versionen unterschiedliche Normalformen besaßen.
Für Anwendungen, die auch über diese Versionsgrenze hinweg absolute Stabilität benötigen, gibt es einfache Algorithmen, um zwischen den Normalisierungen zu wechseln.
Anwendungen
Die meistverbreitete Normalform in Anwendungen ist NFC. Sie wird unter anderem vom World Wide Web Consortium für XML und HTML empfohlen[2] und auch für JavaScript verwendet,[3] indem der Code vor weiterer Verarbeitung in diese Form überführt wird.
Die kanonischen Normalisierungen stellen sicher, dass äquivalente Daten nicht in unterschiedliche Formen persistiert werden, und gewährleisten damit eine konsistente Datenhaltung.
Die kompatiblen Normalisierungen können etwa für eine Suche verwendet werden, bei der es auf kleine optische Differenzen nicht ankommen soll. Allgemeine Normalisierungen können auf den Unicode-Normalisierungen aufbauen.
Siehe auch
Quellen
- Julie D. Allen et al.: The Unicode Standard. Version 6.2 – Core Specification. The Unicode Consortium, Mountain View, CA, 2012. ISBN 978-1-936213-07-8. (online)
- Mark Davis, Ken Whistler: Unicode Standard Annex #15: Unicode Normalization Forms. Revision 37.
Einzelnachweise
- Unicode Character Encoding Stability Policy: Normalization Stability. Abgerufen am 1. Dezember 2012.
- Martin J. Dürst et al.: Character Model for the World Wide Web 1.0: Fundamentals. online, abgerufen am 1. Dezember 2012
- ECMAScript Language Specification. 5.1 Edition, online, abgerufen am 1. Dezember 2012
Weblinks
- Unicode-FAQ zur Normalisierung (englisch)
- Normalization Browser des ICU-Projekts (englisch)