Das ICU-Projekt (das jetzt auch eine PHP-Bibliothek enthält) enthält die Klassen, die zur Normalisierung von UTF-8-Zeichenfolgen erforderlich sind, um den Vergleich von Werten bei der Suche zu erleichtern.
Ich versuche jedoch herauszufinden, was dies für Anwendungen bedeutet . In welchen Fällen möchte ich beispielsweise "Kanonische Äquivalenz" anstelle von "Kompatibilitätsäquivalenz" oder umgekehrt?
php
c
unicode
unicode-normalization
Xeoncross
quelle
quelle
(begin curved line) (char1) (char2) … (charN) (end curved line)
anstatt dieser :(curved line marker prefix) (char1) (curved line marker prefix) (char2) (curved line marker prefix) (char2)
. Mit anderen Worten, minimale Einheit, die gerendert werden kann?Antworten:
Alles, was Sie nie über Unicode-Normalisierung wissen wollten
Kanonische Normalisierung
Unicode bietet mehrere Möglichkeiten zum Codieren einiger Zeichen, insbesondere von Zeichen mit Akzent. Die kanonische Normalisierung ändert die Codepunkte in eine kanonische Codierungsform. Die resultierenden Codepunkte sollten mit den ursprünglichen identisch sein, mit Ausnahme von Fehlern in den Schriftarten oder der Rendering-Engine.
Wann zu verwenden
Da die Ergebnisse identisch erscheinen, ist es immer sicher, eine kanonische Normalisierung auf eine Zeichenfolge anzuwenden, bevor diese gespeichert oder angezeigt wird, solange Sie tolerieren können, dass das Ergebnis nicht Bit für Bit mit der Eingabe identisch ist.
Die kanonische Normalisierung erfolgt in zwei Formen: NFD und NFC. Die beiden sind in dem Sinne äquivalent, dass man ohne Verlust zwischen diesen beiden Formen konvertieren kann. Der Vergleich zweier Zeichenfolgen unter NFC führt immer zum gleichen Ergebnis wie der Vergleich unter NFD.
NFD
NFD hat die Zeichen vollständig erweitert. Dies ist die schnellere zu berechnende Normalisierungsform, die jedoch zu mehr Codepunkten führt (dh mehr Platz benötigt).
Wenn Sie nur zwei Zeichenfolgen vergleichen möchten, die noch nicht normalisiert sind, ist dies die bevorzugte Normalisierungsform, es sei denn, Sie wissen, dass Sie eine Kompatibilitätsnormalisierung benötigen.
NFC
NFC kombiniert Codepunkte nach Möglichkeit neu, nachdem der NFD-Algorithmus ausgeführt wurde. Dies dauert etwas länger, führt jedoch zu kürzeren Saiten.
Kompatibilitätsnormalisierung
Unicode enthält auch viele Zeichen, die wirklich nicht dazu gehören, aber in älteren Zeichensätzen verwendet wurden. Unicode fügte diese hinzu, damit Text in diesen Zeichensätzen als Unicode verarbeitet und dann ohne Verlust zurückkonvertiert werden kann.
Die Kompatibilitätsnormalisierung konvertiert diese in die entsprechende Folge von "echten" Zeichen und führt auch eine kanonische Normalisierung durch. Die Ergebnisse der Kompatibilitätsnormalisierung sind möglicherweise nicht mit den Originalen identisch.
Zeichen, die Formatierungsinformationen enthalten, werden durch Zeichen ersetzt, die dies nicht tun. Zum Beispiel wird der Charakter in
⁹
konvertiert9
. Andere beinhalten keine Formatierungsunterschiede. Beispielsweise wird das römische ZiffernzeichenⅨ
in reguläre Buchstaben umgewandeltIX
.Sobald diese Transformation durchgeführt wurde, ist es offensichtlich nicht mehr möglich, verlustfrei zum ursprünglichen Zeichensatz zurückzukehren.
Wann zu verwenden
Das Unicode-Konsortium schlägt vor, die Kompatibilitätsnormalisierung wie eine
ToUpperCase
Transformation zu betrachten. Es ist etwas, das unter bestimmten Umständen nützlich sein kann, aber Sie sollten es nicht einfach so oder so anwenden.Ein ausgezeichneter Anwendungsfall wäre eine Suchmaschine, da Sie wahrscheinlich eine
9
passende Suche wünschen würden⁹
.Eine Sache, die Sie wahrscheinlich nicht tun sollten, ist das Ergebnis der Anwendung der Kompatibilitätsnormalisierung auf den Benutzer anzuzeigen.
NFKC / NFKD
Das Kompatibilitätsnormalisierungsformular gibt es in zwei Formen: NFKD und NFKC. Sie haben die gleiche Beziehung wie zwischen NFD und C.
Jede Zeichenfolge in NFKC ist von Natur aus auch in NFC enthalten, und dies gilt auch für NFKD und NFD. Also
NFKD(x)=NFD(NFKC(x))
undNFKC(x)=NFC(NFKD(x))
usw.Fazit
Wenn Sie Zweifel haben, fahren Sie mit der kanonischen Normalisierung fort. Wählen Sie NFC oder NFD basierend auf dem anwendbaren Kompromiss zwischen Platz und Geschwindigkeit oder basierend auf den Anforderungen, die für etwas erforderlich sind, mit dem Sie zusammenarbeiten.
quelle
NFC(x)=Recompose(NFD(x))
.Einige Zeichen, z. B. ein Buchstabe mit einem Akzent (z. B.
é
), können auf zwei Arten dargestellt werden - als einzelner CodepunktU+00E9
oder als einfacher Buchstabe, gefolgt von einer kombinierten AkzentmarkeU+0065 U+0301
. Bei der normalen Normalisierung wird eine davon ausgewählt, um sie immer darzustellen (der einzelne Codepunkt für NFC, die Kombinationsform für NFD).Für Zeichen, die durch mehrere Sequenzen von Basiszeichen und Kombinationsmarkierungen dargestellt werden können (z. B. "s, Punkt unten, Punkt oben" oder Punkt oben und Punkt unten setzen oder ein Basiszeichen verwenden, das bereits einen der Punkte enthält), wird NFD dies tun Wählen Sie auch eine davon aus (siehe unten zuerst, wie es passiert)
Die Kompatibilitätszerlegungen enthalten eine Reihe von Zeichen, die eigentlich keine Zeichen sein sollten, sondern darauf zurückzuführen sind, dass sie in Legacy-Codierungen verwendet wurden. Durch die normale Normalisierung werden diese nicht vereinheitlicht (um die Integrität des Roundtrips zu gewährleisten - dies ist kein Problem für das Kombinieren von Formularen, da keine Legacy-Codierung (außer einer Handvoll vietnamesischer Codierungen) beide verwendet), die Kompatibilitätsnormalisierung jedoch. Denken Sie an das "kg" -Kilogrammzeichen, das in einigen ostasiatischen Codierungen (oder an Katakana und Alphabet mit halber / voller Breite) oder an die "fi" -Ligatur in MacRoman vorkommt.
Weitere Informationen finden Sie unter http://unicode.org/reports/tr15/ .
quelle
Normale Formen (von Unicode, keine Datenbanken) befassen sich hauptsächlich (ausschließlich?) Mit Zeichen, die diakritische Zeichen aufweisen. Unicode bietet einigen Zeichen "eingebaute" diakritische Zeichen, wie z. B. U + 00C0, "Latin Capital A with Grave". Das gleiche Zeichen kann aus einer "lateinischen Hauptstadt A" (U + 0041) mit einem "Combining Grave Accent" (U + 0300) erstellt werden. Dies bedeutet, dass die beiden Sequenzen das gleiche resultierende Zeichen erzeugen, ein Byte für Byte Ein Vergleich zeigt, dass sie völlig anders sind.
Normalisierung ist ein Versuch, damit umzugehen. Durch das Normalisieren wird sichergestellt (oder zumindest versucht), dass alle Zeichen auf dieselbe Weise codiert werden - entweder alle mit einem separaten kombinierten diakritischen Zeichen, falls erforderlich, oder alle, wo immer möglich, mit einem einzigen Codepunkt. Unter dem Gesichtspunkt des Vergleichs spielt es keine Rolle, welche Menge Sie wählen - so ziemlich jede normalisierte Zeichenfolge wird richtig mit einer anderen normalisierten Zeichenfolge verglichen.
In diesem Fall bedeutet "Kompatibilität" Kompatibilität mit Code, bei dem davon ausgegangen wird, dass ein Codepunkt einem Zeichen entspricht. Wenn Sie solchen Code haben, möchten Sie wahrscheinlich das normale Kompatibilitätsformular verwenden. Obwohl ich es noch nie direkt gesehen habe, implizieren die Namen der normalen Formen, dass das Unicode-Konsortium es für vorzuziehen hält, separate kombinierte diakritische Zeichen zu verwenden. Dies erfordert mehr Intelligenz, um die tatsächlichen Zeichen in einer Zeichenfolge zu zählen (sowie Dinge wie das intelligente Brechen einer Zeichenfolge), ist jedoch vielseitiger.
Wenn Sie die Intensivstation voll ausnutzen, besteht die Möglichkeit, dass Sie die kanonische Normalform verwenden möchten. Wenn Sie versuchen, selbst Code zu schreiben, der (zum Beispiel) davon ausgeht, dass ein Codepunkt einem Zeichen entspricht, möchten Sie wahrscheinlich die normale Kompatibilitätsform, die dies so oft wie möglich wahr macht.
quelle
"o\x{332}\x{303}\x{304}"
und NFC ist"\x{22D}\x{332}"
. Für die zweite ist NFD"o\x{332}\x{304}\x{303}"
und NFC ist"\x{14D}\x{332}\x{303}"
. Es gibt jedoch viele nicht-kanonische Möglichkeiten, die diesen kanonisch äquivalent sind. Die Normalisierung ermöglicht den binären Vergleich kanonisch äquivalenter Grapheme.Wenn zwei Unicode-Zeichenfolgen kanonisch äquivalent sind, sind die Zeichenfolgen tatsächlich gleich und verwenden nur unterschiedliche Unicode-Sequenzen. Zum Beispiel kann Ä entweder mit dem Zeichen Ä oder einer Kombination von A und ◌̈ dargestellt werden.
Wenn die Zeichenfolgen nur kompatibel sind, sind die Zeichenfolgen nicht unbedingt gleich, können jedoch in einigen Kontexten gleich sein. ZB könnte ff als ff angesehen werden.
Wenn Sie also Zeichenfolgen vergleichen, sollten Sie die kanonische Äquivalenz verwenden, da die Kompatibilitätsäquivalenz keine echte Äquivalenz ist.
Wenn Sie jedoch eine Reihe von Zeichenfolgen sortieren möchten, ist es möglicherweise sinnvoll, die Kompatibilitätsäquivalenz zu verwenden, da diese nahezu identisch sind.
quelle
Das ist eigentlich ziemlich einfach. UTF-8 hat tatsächlich mehrere verschiedene Darstellungen desselben "Charakters". (Ich verwende Zeichen in Anführungszeichen, da sie byteweise unterschiedlich sind, aber praktisch gleich). Ein Beispiel finden Sie im verknüpften Dokument.
Das Zeichen "Ç" kann als Bytefolge 0xc387 dargestellt werden. Es kann aber auch durch a
C
(0x43) gefolgt von der Bytefolge 0xcca7 dargestellt werden. Man kann also sagen, dass 0xc387 und 0x43cca7 dasselbe Zeichen sind. Der Grund, der funktioniert, ist, dass 0xcca7 eine Kombinationsmarke ist; das heißt, es nimmt den Charakter davor (aC
hier) und modifiziert ihn.Was nun den Unterschied zwischen kanonischer Äquivalenz und Kompatibilitätsäquivalenz betrifft, müssen wir uns die Zeichen im Allgemeinen ansehen.
Es gibt zwei Arten von Zeichen, diejenigen, die durch den Wert Bedeutung vermitteln , und diejenigen, die ein anderes Zeichen nehmen und es ändern. 9 ist ein bedeutungsvoller Charakter. Ein Superskript ⁹ nimmt diese Bedeutung an und ändert sie durch Präsentation. Kanonisch haben sie also unterschiedliche Bedeutungen, aber sie repräsentieren immer noch den Grundcharakter.
Bei der kanonischen Äquivalenz gibt die Byte-Sequenz dasselbe Zeichen mit derselben Bedeutung wieder. Kompatibilitätsäquivalenz ist, wenn die Byte-Sequenz ein anderes Zeichen mit derselben Basisbedeutung wiedergibt (obwohl es möglicherweise geändert wird). Die 9 und ⁹ sind Kompatibilitätsäquivalente, da beide "9" bedeuten, aber nicht kanonisch äquivalent, da sie nicht dieselbe Darstellung haben.
quelle
Ob kanonische Äquivalenz oder Kompatibilitätsäquivalenz für Sie relevanter ist, hängt von Ihrer Anwendung ab. Die ASCII-Denkweise bei String-Vergleichen entspricht in etwa der kanonischen Äquivalenz, aber Unicode repräsentiert viele Sprachen. Ich glaube nicht, dass man davon ausgehen kann, dass Unicode alle Sprachen so codiert, dass Sie sie wie westeuropäisches ASCII behandeln können.
Die Abbildungen 1 und 2 zeigen gute Beispiele für die beiden Äquivalenzarten. Unter Kompatibilitätsäquivalenz sieht es so aus, als würde dieselbe Zahl in Unter- und Superskriptform gleich verglichen. Aber ich bin mir nicht sicher, ob das das gleiche Problem löst wie die kursive arabische Form oder die gedrehten Zeichen.
Die harte Wahrheit der Unicode-Textverarbeitung ist, dass Sie tief über die Textverarbeitungsanforderungen Ihrer Anwendung nachdenken und diese dann so gut wie möglich mit den verfügbaren Tools angehen müssen. Das geht nicht direkt auf Ihre Frage ein, aber eine detailliertere Antwort würde Sprachexperten für jede der Sprachen erfordern, die Sie unterstützen möchten.
quelle
Das Problem beim Vergleichen von Zeichenfolgen : Zwei Zeichenfolgen mit einem Inhalt, der für die meisten Anwendungen gleichwertig ist, können unterschiedliche Zeichenfolgen enthalten.
Siehe Unicodes kanonische Äquivalenz : Wenn der Vergleichsalgorithmus einfach ist (oder schnell sein muss), wird die Unicode-Äquivalenz nicht durchgeführt. Dieses Problem tritt beispielsweise beim kanonischen XML-Vergleich auf, siehe http://www.w3.org/TR/xml-c14n
Um dieses Problem zu vermeiden ... Welcher Standard ist zu verwenden? "erweitertes UTF8" oder "kompaktes UTF8"?
Verwenden Sie "ç" oder "c + ◌̧".
W3C und andere (z. B. Dateinamen ) schlagen vor, "komponiert als kanonisch" zu verwenden (beachten Sie C der "kompaktesten" kürzeren Zeichenfolgen) ... Also,
Der Standard ist C ! Verwenden Sie im Zweifelsfall NFC
Für die Interoperabilität und für die Auswahl "Konvention über Konfiguration" wird die Verwendung von NFC empfohlen , um externe Zeichenfolgen zu "kanonisieren". Um beispielsweise kanonisches XML zu speichern, speichern Sie es im "FORM_C". Die CSV in der Web-Arbeitsgruppe des W3C empfiehlt ebenfalls NFC (Abschnitt 7.2).
PS: de "FORM_C" ist das Standardformular in den meisten Bibliotheken. Ex. in PHPs normalizer.isnormalized () .
Der Begriff " Kompostierungsform " (
FORM_C
) wird sowohl für "eine Zeichenfolge in der C-kanonischen Form" (das Ergebnis einer NFC-Transformation) als auch für die Verwendung eines Transformationsalgorithmus verwendet ... Siehe http: //www.macchiato.com/unicode/nfc-faqHinweis: Zum Testen der Normalisierung kleiner Zeichenfolgen (reine UTF-8- oder XML-Entitätsreferenzen) können Sie diesen Test / Normalisierungs-Online-Konverter verwenden .
quelle