Letzten Monat habe ich eine detaillierte Einführung in den Unicode-Zeichensatz und seine Unterstützung in der JavaScript-Sprache geteilt. Das Folgende ist die Abschrift der Rede, die dieses Mal gehalten wurde.
1. Was ist Unicode?
Unicode entstand aus einer sehr einfachen Idee: Alle Zeichen der Welt in einem Satz zusammenfassen. Solange der Computer diesen Zeichensatz unterstützt, kann er alle Zeichen anzeigen und es treten keine verstümmelten Zeichen mehr auf.
Es beginnt bei 0 und weist jedem Symbol eine Zahl zu, die als „Codepunkt“ bezeichnet wird. Beispielsweise ist das Symbol für Codepunkt 0 null (was bedeutet, dass alle Binärbits 0 sind).
In der obigen Formel gibt U an, dass die unmittelbar folgende Hexadezimalzahl der Unicode-Codepunkt ist.
Derzeit ist die neueste Version von Unicode Version 7.0, die insgesamt 109.449 Symbole enthält, darunter 74.500 chinesische, japanische und koreanische Zeichen. Schätzungsweise stammen mehr als zwei Drittel der weltweit existierenden Symbole aus ostasiatischen Schriften. Der Codepunkt für „gut“ auf Chinesisch ist beispielsweise 597D im Hexadezimalformat.
Bei so vielen Symbolen wird Unicode nicht auf einmal definiert, sondern in Partitionen. Jeder Bereich kann 65536 (216) Zeichen speichern, was als Ebene bezeichnet wird. Derzeit gibt es insgesamt 17 (25) Ebenen, was bedeutet, dass die Größe des gesamten Unicode-Zeichensatzes nun 221 beträgt.
Die ersten 65536 Zeichenbits werden als Basisebene bezeichnet (Abkürzung BMP). Der Codepunktbereich reicht von 0 bis 216-1. Er ist hexadezimal geschrieben und reicht von U 0000 bis U FFFF. Alle gebräuchlichen Zeichen werden auf dieser Ebene platziert, die die erste von Unicode definierte und angekündigte Ebene ist.
Die restlichen Zeichen werden in der Hilfsebene (abgekürzt als SMP) platziert und die Codepunkte reichen von U 010000 bis U 10FFFF.
2. UTF-32 und UTF-8
Unicode legt nur den Codepunkt jedes Zeichens fest. Welche Art von Bytereihenfolge zur Darstellung dieses Codepunkts verwendet wird, hängt von der Codierungsmethode ab.
Die intuitivste Codierungsmethode besteht darin, dass jeder Codepunkt durch vier Bytes dargestellt wird und der Byteinhalt eins zu eins dem Codepunkt entspricht. Diese Kodierungsmethode heißt UTF-32. Beispielsweise wird Codepunkt 0 durch vier Bytes von 0 dargestellt, und Codepunkt 597D werden durch zwei Bytes von 0 vorangestellt.
Der Vorteil von UTF-32 besteht darin, dass die Konvertierungsregeln einfach und intuitiv sind und die Sucheffizienz hoch ist. Der Nachteil besteht darin, dass dadurch Platz verschwendet wird. Für denselben englischen Text ist er viermal größer als die ASCII-Kodierung. Dieser Mangel ist so schwerwiegend, dass niemand diese Kodierungsmethode tatsächlich verwendet. Der HTML-5-Standard schreibt eindeutig vor, dass Webseiten nicht in UTF-32 kodiert werden dürfen.
Was die Menschen wirklich brauchten, war eine platzsparende Kodierungsmethode, die zur Geburt von UTF-8 führte. UTF-8 ist eine Codierungsmethode mit variabler Länge und Zeichenlängen zwischen 1 Byte und 4 Byte. Je häufiger Zeichen verwendet werden, desto kürzer sind die Bytes. Die ersten 128 Zeichen werden durch nur 1 Byte dargestellt, was genau dem ASCII-Code entspricht.
Nummernkreis Bytes 0x0000 - 0x007F10x0080 - 0x07FF20x0800 - 0xFFFF30x010000 - 0x10FFFF4
Aufgrund der platzsparenden Eigenschaften von UTF-8 ist es zur am häufigsten verwendeten Webseitenkodierung im Internet geworden. Es hat jedoch wenig mit dem heutigen Thema zu tun, daher werde ich nicht näher darauf eingehen. Informationen zu bestimmten Transkodierungsmethoden finden Sie unter „Hinweise zur Zeichenkodierung“ .
3. Einführung in UTF-16
Die UTF-16-Kodierung liegt zwischen UTF-32 und UTF-8 und kombiniert die Eigenschaften von Kodierungsmethoden mit fester und variabler Länge.
Die Codierungsregeln sind sehr einfach: Zeichen in der Basisebene belegen 2 Bytes und Zeichen in der Hilfsebene belegen 4 Bytes. Das heißt, die Kodierungslänge von UTF-16 beträgt entweder 2 Byte (U 0000 bis U FFFF) oder 4 Byte (U 010000 bis U 10FFFF).
Wenn wir also auf zwei Bytes stoßen, woher wissen wir, ob es sich um ein Zeichen selbst handelt oder ob es zusammen mit den anderen beiden Bytes interpretiert werden muss?
Es ist sehr clever. Ich weiß nicht, ob es ein absichtliches Design ist. In der Grundebene ist von U D800 bis U DFFF ein leeres Segment, das heißt, diese Codepunkte entsprechen keinem Zeichen. Daher kann dieses leere Segment zum Zuordnen von Hilfsebenenzeichen verwendet werden.
Konkret gibt es 220 Zeichenbits in der Hilfsebene, was bedeutet, dass mindestens 20 Binärbits erforderlich sind, um diesen Zeichen zu entsprechen. UTF-16 teilt diese 20 Bits in zwei Hälften. Die ersten 10 Bits werden von U D800 auf U DBFF (Speicherplatzgröße 210) abgebildet, das sogenannte High-Bit (H), und die letzten 10 Bits werden von U DC00 auf U DFFF abgebildet. Raumgröße 210), genannt Low-Bit (L). Dies bedeutet, dass ein Hilfsebenenzeichen in zwei grundlegende Ebenenzeichendarstellungen aufgeteilt wird.
Wenn wir also auf zwei Bytes stoßen und feststellen, dass ihre Codepunkte zwischen U D800 und U DBFF liegen, können wir daraus schließen, dass die Codepunkte der folgenden zwei Bytes zwischen U DC00 und U DBFF liegen sollten, also diese vier Bytes müssen zusammen gelesen werden.
4. UTF-16-Transkodierungsformel
Unterscheiden Sie beim Konvertieren von Unicode-Codepunkten in UTF-16 zunächst, ob es sich um ein einfaches flaches Zeichen oder ein flaches Hilfszeichen handelt. Wenn ersteres der Fall ist, konvertieren Sie den Codepunkt direkt in die entsprechende Hexadezimalform mit einer Länge von zwei Bytes.
Wenn es sich um ein flaches Hilfszeichen handelt, bietet Unicode Version 3.0 eine Transkodierungsformel.
Nehmen Sie als Beispiel das Zeichen . Es handelt sich um ein Hilfsebenenzeichen mit dem Codepunkt U 1D306. Der Berechnungsprozess für die Konvertierung in UTF-16 ist wie folgt.
Daher ist die UTF-16-Codierung des Zeichens 0xD834 DF06 und die Länge beträgt vier Bytes.
5. Welche Kodierung verwendet JavaScript?
Die JavaScript-Sprache verwendet den Unicode-Zeichensatz, unterstützt jedoch nur eine Kodierungsmethode.
Diese Kodierung ist weder UTF-16 noch UTF-8 noch UTF-32. Keine der oben genannten Codierungsmethoden wird in JavaScript verwendet.
JavaScript verwendet UCS-2!
6. UCS-2-Kodierung
Warum tauchte plötzlich ein UCS-2 auf? Dies erfordert ein wenig Geschichte.
In der Zeit vor dem Aufkommen des Internets gab es zwei Teams, die alle einen einheitlichen Zeichensatz erstellen wollten. Das eine ist das 1989 gegründete Unicode-Team und das andere ist das frühere UCS-Team, das 1988 gegründet wurde. Als sie von der Existenz des anderen erfuhren, kamen sie schnell zu einer Einigung: Die Welt braucht keine zwei einheitlichen Zeichensätze.
Im Oktober 1991 beschlossen die beiden Teams, die Zeichensätze zusammenzuführen. Mit anderen Worten, von nun an wird nur noch ein Zeichensatz veröffentlicht, nämlich Unicode, und die zuvor veröffentlichten Zeichensätze werden überarbeitet. Die Codepunkte von UCS werden vollständig mit Unicode übereinstimmen.
Die aktuelle Situation war damals, dass der Entwicklungsfortschritt von UCS schneller war als der von Unicode. Bereits 1990 wurde die erste Codierungsmethode UCS-2 angekündigt, bei der 2 Bytes zur Darstellung von Zeichen verwendet wurden, die bereits Codepunkte hatten. (Damals gab es nur eine Ebene, die Basisebene, also reichten 2 Bytes aus.) Die UTF-16-Kodierung wurde erst im Juli 1996 angekündigt, und es wurde eindeutig bekannt gegeben, dass es sich um eine Obermenge von UCS-2 handelte , die Grundebenenzeichen wurden von der UCS-2-Kodierung übernommen, Hilfsebenenzeichen definieren eine 4-Byte-Darstellungsmethode.
Einfach ausgedrückt besteht die Beziehung zwischen den beiden darin, dass UTF-16 UCS-2 ersetzt oder UCS-2 in UTF-16 integriert ist. Jetzt gibt es also nur noch UTF-16, kein UCS-2.
7. Hintergrund der Geburt von JavaScript
Warum wählt JavaScript nicht das fortschrittlichere UTF-16, sondern verwendet das veraltete UCS-2?
Die Antwort ist einfach: Entweder Sie wollen es nicht oder Sie können es nicht. Denn als die JavaScript-Sprache erschien, gab es keine UTF-16-Kodierung.
Im Mai 1995 verbrachte Brendan Eich 10 Tage damit, die JavaScript-Sprache zu entwerfen, im November des folgenden Jahres kam die erste Interpretations-Engine heraus, Netscape reichte den Sprachstandard offiziell bei ECMA ein (Einzelheiten zum gesamten Prozess); siehe 《Die Geburt von JavaScript》). Wenn Sie die Veröffentlichungszeit von UTF-16 (Juli 1996) vergleichen, werden Sie verstehen, dass Netscape zu diesem Zeitpunkt keine andere Wahl hatte, sondern nur UCS-2 als Kodierungsmethode verfügbar war!
8. Einschränkungen der JavaScript-Zeichenfunktionen
Da JavaScript nur UCS-2-Codierung verarbeiten kann, sind alle Zeichen in dieser Sprache 2 Bytes lang. Wenn es sich um ein 4-Byte-Zeichen handelt, wird es als zwei Doppelbyte-Zeichen behandelt. Davon sind alle Zeichenfunktionen von JavaScript betroffen und können keine korrekten Ergebnisse zurückgeben.
Nehmen wir immer noch das Zeichen als Beispiel. Seine UTF-16-Kodierung beträgt 4 Bytes von 0xD834 DF06. Das Problem tritt auf. Die 4-Byte-Kodierung gehört nicht zu UCS-2 und betrachtet sie nur als zwei separate Zeichen, U D834 und U DF06. Wie bereits erwähnt, sind diese beiden Codepunkte leer, sodass JavaScript davon ausgeht, dass eine Zeichenfolge ist, die aus zwei leeren Zeichen besteht!
Der obige Code zeigt an, dass JavaScript die Länge des Zeichens als 2 ansieht, das erste erhaltene Zeichen ein Nullzeichen ist und der Codepunkt des ersten erhaltenen Zeichens 0xDB34 ist. Keines dieser Ergebnisse ist korrekt!
Um dieses Problem zu lösen, müssen Sie den Codepunkt beurteilen und ihn dann manuell anpassen. Das Folgende ist die korrekte Methode zum Durchlaufen einer Zeichenfolge.
Der obige Code zeigt an, dass beim Durchlaufen einer Zeichenfolge eine Beurteilung des Codepunkts vorgenommen werden muss. Solange dieser im Bereich von 0xD800 bis 0xDBFF liegt, muss er zusammen mit den folgenden 2 Bytes gelesen werden.
Ähnliche Probleme bestehen bei allen JavaScript-Funktionen zur Zeichenmanipulation.
String.prototype.replace()String.prototype.substring()String.prototype.slice()...
Die oben genannten Funktionen gelten nur für 2-Byte-Codepunkte. Um 4-Byte-Codepunkte korrekt zu verarbeiten, müssen Sie Ihre eigenen Versionen nacheinander bereitstellen, um den Codepunktbereich des aktuellen Zeichens zu bestimmen.
9. ECMAScript 6
Die nächste Version von JavaScript, ECMAScript 6 (kurz ES6), hat die Unicode-Unterstützung erheblich verbessert und dieses Problem im Wesentlichen gelöst.
(1) Zeichen richtig identifizieren
ES6 kann 4-Byte-Codepunkte automatisch erkennen. Daher ist die Iteration über die Zeichenfolge viel einfacher.
Aus Kompatibilitätsgründen verhält sich das Längenattribut jedoch weiterhin wie ursprünglich. Um die richtige Länge der Zeichenfolge zu erhalten, können Sie die folgende Methode verwenden.
(2) Codepunktdarstellung
Mit JavaScript können Unicode-Zeichen direkt durch Codepunkte dargestellt werden, die als „Slash-u-Codepunkte“ geschrieben werden.
Diese Darstellung gilt jedoch nicht für 4-Byte-Codepunkte. ES6 behebt dieses Problem und die Codepunkte können korrekt erkannt werden, solange sie in geschweifte Klammern gesetzt werden.
(3) String-Verarbeitungsfunktion
ES6 fügt mehrere neue Funktionen hinzu, die speziell 4-Byte-Codepunkte verarbeiten.
String.fromCodePoint(): Gibt das entsprechende Zeichen vom Unicode-Codepunkt zurück String.prototype.codePointAt(): Gibt den entsprechenden Codepunkt vom Zeichen zurück String.prototype.at(): Gibt das Zeichen an der angegebenen Position in zurück die Zeichenfolge
(4) Regulärer Ausdruck
ES6 bietet den u-Modifikator, der das Hinzufügen von 4-Byte-Codepunkten zu regulären Ausdrücken unterstützt.
(5) Unicode-Regularisierung
Zusätzlich zu Buchstaben haben einige Zeichen auch zusätzliche Symbole . Im chinesischen Pinyin Ǒ beispielsweise sind die Töne über den Buchstaben zusätzliche Symbole. Für viele europäische Sprachen sind Tonzeichen sehr wichtig.
Unicode bietet zwei Darstellungsmethoden. Einer ist ein einzelnes Zeichen mit einem zusätzlichen Symbol, das heißt, ein Codepunkt stellt ein Zeichen dar, der Codepunkt von Ǒ ist beispielsweise U 01D1; der andere ist das zusätzliche Symbol als separater Codepunkt, kombiniert mit dem Hauptzeichen. Das heißt, zwei Codes. Ein Punkt stellt ein Zeichen dar, zum Beispiel kann Ǒ als O (U 004F) ˇ (U 030C) geschrieben werden.
//Methode 2
'u004Fu030C'
// 'Ǒ'
Diese beiden Darstellungsmethoden sind visuell und semantisch genau gleich und sollten als gleichwertig behandelt werden. JavaScript kann dies jedoch nicht erkennen.
ES6 bietet die Normalisierungsmethode, die eine „Unicode-Normalisierung“ ermöglicht, d. h. die Konvertierung der beiden Methoden in die gleiche Sequenz.
Eine weitere Einführung in ES6 finden Sie unter „Einführung in ECMAScript 6“ .
==========================