Dieses Kapitel ist eine kurze Einführung in Unicode und wie es in JavaScript behandelt wird.
Der erste Entwurfsvorschlag für Unicode wurde 1988 veröffentlicht. Die Arbeit wurde danach fortgesetzt und die Arbeitsgruppe erweiterte sich. Das Unicode Consortium wurde am 3. Januar 1991 eingetragen.
Das Unicode-Konsortium ist eine gemeinnützige Körperschaft, die sich der Entwicklung, Pflege und Förderung von Software-Internationalisierungsstandards und -daten widmet, insbesondere dem Unicode-Standard [...].
Der erste Band des Unicode 1.0-Standards wurde im Oktober 1991 und der zweite im Juni 1992 veröffentlicht.
Wenn eine Codeeinheit größer als ein einzelnes Byte ist, ist die Byte-Reihenfolge wichtig. Das BOM ist ein einzelnes Pseudozeichen (möglicherweise als mehrere Codeeinheiten kodiert) am Anfang eines Textes, das anzeigt, ob die Codeeinheiten Big-Endian (die höchstwertigen Bytes kommen zuerst) oder Little-Endian (die niederwertigsten Bytes kommen zuerst) sind. Standardmäßig sind Texte ohne BOM Big-Endian. Das BOM zeigt auch die verwendete Kodierung an; es ist unterschiedlich für UTF-8, UTF-16 usw. Darüber hinaus dient es als Marker für Unicode, wenn Webbrowser keine anderen Informationen über die Kodierung eines Textes haben. Das BOM wird jedoch aus mehreren Gründen nicht sehr oft verwendet:
Jedem Unicode-Zeichen werden von der Spezifikation mehrere Eigenschaften zugewiesen, von denen einige hier aufgelistet sind:
Name. Ein englischer Name, bestehend aus Großbuchstaben A–Z, Ziffern 0–9, Bindestrich (-) und Leerzeichen. Zwei Beispiele
Der Bereich der Codepunkte war ursprünglich 16 Bit. Mit Unicode Version 2.0 (Juli 1996) wurde er erweitert: Er ist nun in 17 Ebenen unterteilt, nummeriert von 0 bis 16. Jede Ebene umfasst 16 Bit (in hexadezimaler Notation: 0x0000–0xFFFF). Daher enthalten in den folgenden hexadezimalen Bereichen die Ziffern jenseits der vier untersten die Nummer der Ebene.
Die Ebenen 1–16 werden als supplementäre Ebenen oder astrale Ebenen bezeichnet.
UTF-32 (Unicode Transformation Format 32) ist ein Format mit 32-Bit-Codeeinheiten. Jeder Codepunkt kann durch eine einzelne Codeeinheit kodiert werden, was dies zur einzigen Kodierung mit fester Länge macht; bei anderen Kodierungen variiert die zur Kodierung eines Punkts benötigte Anzahl von Einheiten.
UTF-16 ist ein Format mit 16-Bit-Codeeinheiten, das ein bis zwei Einheiten zur Darstellung eines Codepunkts benötigt. BMP-Codepunkte können durch einzelne Codeeinheiten dargestellt werden. Höhere Codepunkte sind 20 Bit (16 mal 16 Bit), nachdem 0x10000 (der Bereich des BMP) subtrahiert wurde. Diese Bits werden als zwei Codeeinheiten (ein sogenanntes Surrogatpaar) kodiert:
Die folgende Tabelle (angepasst aus Unicode Standard 6.2.0, Tabelle 3-5) visualisiert, wie die Bits verteilt sind
| Codepunkt | UTF-16 Codeeinheit(en) |
xxxxxxxxxxxxxxxx (16 Bit) | xxxxxxxxxxxxxxxx |
pppppxxxxxxyyyyyyyyyy (21 Bit = 5+6+10 Bit) | 110110qqqqxxxxxx 110111yyyyyyyyyy (qqqq = ppppp − 1) |
Um dieses Kodierungsschema zu ermöglichen, hat das BMP ein Loch mit ungenutzten Codepunkten, deren Bereich 0xD800–0xDFFF ist. Daher sind die Bereiche von führenden Surrogaten, nachfolgenden Surrogaten und BMP-Codepunkten disjunkt, was die Dekodierung robust gegenüber Fehlern macht. Die folgende Funktion kodiert einen Codepunkt als UTF-16 (später sehen wir ein Beispiel für seine Verwendung)
functiontoUTF16(codePoint){varTEN_BITS=parseInt('1111111111',2);functionu(codeUnit){return'\\u'+codeUnit.toString(16).toUpperCase();}if(codePoint<=0xFFFF){returnu(codePoint);}codePoint-=0x10000;// Shift right to get to most significant 10 bitsvarleadingSurrogate=0xD800|(codePoint>>10);// Mask to get least significant 10 bitsvartrailingSurrogate=0xDC00|(codePoint&TEN_BITS);returnu(leadingSurrogate)+u(trailingSurrogate);}
UCS-2, ein veraltetes Format, verwendet 16-Bit-Codeeinheiten zur Darstellung (nur!) der Codepunkte des BMP. Als der Bereich der Unicode-Codepunkte über 16 Bit hinaus erweitert wurde, ersetzte UTF-16 UCS-2.
Wenn das höchste Bit nicht 0 ist, gibt die Anzahl der Einsen vor der Null an, wie viele Codeeinheiten in einer Sequenz vorhanden sind. Alle Codeeinheiten nach der ersten haben das Bitpräfix 10. Daher sind die Bereiche von Anfangs-Codeeinheiten und nachfolgenden Codeeinheiten disjunkt, was bei der Wiederherstellung von Kodierungsfehlern hilft.
UTF-8 ist das beliebteste Unicode-Format geworden. Anfangs war seine Popularität auf seine Abwärtskompatibilität mit ASCII zurückzuführen. Später gewann es aufgrund seiner breiten und konsistenten Unterstützung über Betriebssysteme, Programmierumgebungen und Anwendungen hinweg an Bedeutung.
Intern wird JavaScript-Quellcode als eine Sequenz von UTF-16-Codeeinheiten behandelt. GemäßAbschnitt 6 der ECMAScript-Spezifikation
ECMAScript-Quelltext wird für die Zwecke dieser Spezifikation als Sequenz von Zeichen in der Unicode-Zeichenkodierung, Version 3.0 oder neuer, dargestellt. [...] ECMAScript-Quelltext wird als Sequenz von 16-Bit-Codeeinheiten angenommen. [...] Wenn ein tatsächlicher Quelltext in einer anderen Form als 16-Bit-Codeeinheiten kodiert ist, muss er so verarbeitet werden, als ob er zuerst in UTF-16 konvertiert worden wäre.
In Bezeichnern, Zeichenkettenliteralen und regulären Ausdruckliteralen kann jede Codeeinheit auch über eine Unicode-Escape-Sequenz \uHHHH ausgedrückt werden, wobei HHHH vier hexadezimale Ziffern sind. Zum Beispiel:
> var f\u006F\u006F = 'abc'; > foo 'abc' > var λ = 123; > \u03BB 123
Das bedeutet, dass Sie Unicode-Zeichen in Literalen und Variablennamen verwenden können, ohne den ASCII-Bereich im Quellcode zu verlassen.
In Zeichenkettenliteralen ist eine weitere Art von Escape verfügbar: hexadezimale Escape-Sequenzen mit zweistelligen hexadezimalen Zahlen, die Codeeinheiten im Bereich 0x00–0xFF darstellen. Zum Beispiel:
> '\xF6' === 'ö' true > '\xF6' === '\u00F6' true
Während UTF-16 intern verwendet wird, wird JavaScript-Quellcode normalerweise nicht in diesem Format gespeichert. Wenn ein Webbrowser eine Quelldatei über ein <script>-Tag lädt, ermittelt er die Kodierungwie folgt
Andernfalls, wenn die Datei über HTTP(S) geladen wird, kann der Content-Type-Header eine Kodierung über den charset-Parameter angeben. Zum Beispiel
Content-Type: application/javascript; charset=utf-8
Der korrekte Medientyp (früher bekannt als MIME-Typ) für JavaScript-Dateien ist application/javascript. Ältere Browser (z. B. Internet Explorer 8 und früher) funktionieren jedoch am zuverlässigsten mit text/javascript. Leider ist derStandardwert für das Attribut type von <script>-Tags text/javascript. Zumindest können Sie dieses Attribut für JavaScript weglassen; es gibt keinen Vorteil, es einzuschließen.
<script>-Tag das Attribut charset hat, wird diese Kodierung verwendet. Obwohl das Attribut type einen gültigen Medientyp angibt, darf dieser Typ nicht den Parameter charset haben (wie im oben genannten Content-Type-Header). Dies stellt sicher, dass sich die Werte von charset und type nicht widersprechen.Andernfalls wird die Kodierung des Dokuments verwendet, in dem sich das <script>-Tag befindet. Dies ist zum Beispiel der Anfang eines HTML5-Dokuments, in dem ein <meta>-Tag deklariert, dass das Dokument als UTF-8 kodiert ist
<!doctype html><html><head><metacharset="UTF-8">...
Es wird dringend empfohlen, immer eine Kodierung anzugeben. Wenn Sie dies nicht tun, wird eine lokalisierungsspezifische Standardkodierung verwendet. Mit anderen Worten, die Leute werden die Datei in verschiedenen Ländern unterschiedlich sehen. Nur die untersten 7 Bits sind über Lokalisierungen hinweg relativ stabil.
Meine Empfehlungen lassen sich wie folgt zusammenfassen
Einige Minifizierungs-Tools können Quellcode mit Unicode-Codepunkten über 7 Bit hinaus in „7-Bit-sauberen“ Quellcode übersetzen. Sie tun dies, indem sie Nicht-ASCII-Zeichen durch Unicode-Escapes ersetzen. Zum Beispiel die folgende Aufrufung vonUglifyJS übersetzt die Datei test.js:
uglifyjs -b beautify=false,ascii-only=true test.js
Die Datei test.js sieht so aus
varσ='Köln';
Die Ausgabe von UglifyJS sieht so aus
var\u03c3="K\xf6ln";
Betrachten Sie das folgende negative Beispiel. Eine Zeit lang wurde die Bibliothek D3.js in UTF-8 veröffentlicht. Das führte zu einem Fehler, wenn sie von einer Seite geladen wurde, deren Kodierung nicht UTF-8 war, da der Code Anweisungen wie diese enthielt
varπ=Math.PI,ε=1e-6;
Die Bezeichner π und ε wurden nicht korrekt dekodiert und nicht als gültige Variablennamen erkannt. Darüber hinaus wurden auch einige Zeichenkettenliterale mit Codepunkten über 7 Bit hinaus nicht korrekt dekodiert. Als Workaround konnte man den Code laden, indem man das entsprechende charset-Attribut zum <script>-Tag hinzufügte
<scriptcharset="utf-8"src="d3.js"></script>
Eine JavaScript-Zeichenkette ist eine Sequenz von UTF-16-Codeeinheiten. Laut der ECMAScript-Spezifikation,Abschnitt 8.4
Wenn eine Zeichenkette tatsächliche Textdaten enthält, wird jedes Element als einzelne UTF-16-Codeeinheit betrachtet.
Wie bereits erwähnt, können Sie Unicode-Escape-Sequenzen und hexadezimale Escape-Sequenzen in Zeichenkettenliteralen verwenden. Zum Beispiel können Sie das Zeichen ö erzeugen, indem Sie ein o mit einem Diaeresis (Codepunkt 0x0308) kombinieren:
> console.log('o\u0308')
öDies funktioniert in JavaScript-Kommandozeilen, wie Webbrowser-Konsolen und der Node.js REPL. Sie können diese Art von Zeichenkette auch in das DOM einer Webseite einfügen.
Es gibt viele schöne Unicode-Symboltabellen im Web. Schauen Sie sich Tim Whitlocks„Emoji Unicode Tables“ an und staunen Sie, wie viele Symbole es in modernen Unicode-Schriftarten gibt. Keines der Symbole in der Tabelle sind Bilder; es sind alles Schriftartglyphen. Nehmen wir an, Sie möchten ein Unicode-Zeichen über JavaScript anzeigen, das sich in einer astralen Ebene befindet (offensichtlich besteht ein Risiko, wenn Sie dies tun: Nicht alle Schriftarten unterstützen alle solchen Zeichen). Betrachten Sie zum Beispiel eine Kuh, Codepunkt 0x1F404:
.
Sie können das Zeichen kopieren und direkt in Ihren Unicode-kodierten JavaScript-Quellcode einfügen

JavaScript-Engines dekodieren den Quellcode (der meistens in UTF-8 vorliegt) und erstellen eine Zeichenkette mit zwei UTF-16-Codeeinheiten. Alternativ können Sie die beiden Codeeinheiten selbst berechnen und Unicode-Escape-Sequenzen verwenden. Es gibt Webanwendungen, die diese Berechnung durchführen, wie zum Beispiel:
Die zuvor definierte Funktion toUTF16 führt dies ebenfalls durch
> toUTF16(0x1F404) '\\uD83D\\uDC04'
Das UTF-16-Surrogatpaar (0xD83D, 0xDC04) kodiert tatsächlich die Kuh

Wenn eine Zeichenkette ein Surrogatpaar (zwei Codeeinheiten, die einen einzelnen Codepunkt kodieren) enthält, zählt die length-Eigenschaft nicht mehr Grapheme. Sie zählt Codeeinheiten:

Dies kann über Bibliotheken behoben werden, wie z. B. Mathias Bynens Punycode.js, das mit Node.js gebündelt ist
> var puny = require('punycode');
> puny.ucs2.decode(str).length
1Wenn Sie in Zeichenketten suchen oder sie vergleichen möchten, müssen Sie normalisieren – zum Beispiel über die Bibliothekunorm (von Bjarke Walling).
Die Unterstützung für Unicode in JavaScripts regulären Ausdrücken (sieheKapitel 19) ist sehr begrenzt. Zum Beispiel gibt es keine Möglichkeit, Unicode-Kategorien wie „Großbuchstabe“ abzugleichen.
Zeilenabschlüsse beeinflussen das Matching. Ein Zeilenabschluss ist eines von vier Zeichen, das in der folgenden Tabelle angegeben ist:
| Codeeinheit | Name | Zeichen-Escape-Sequenz |
\u000A | Zeilenumbruch |
|
\u000D | Wagenrücklauf |
|
\u2028 | Zeilentrenner | |
\u2029 | Absatztrenner |
Die folgenden regulären Ausdruckkonstrukte basieren auf Unicode
\s \S (Leerzeichen, Nicht-Leerzeichen) haben Unicode-basierte Definitionen
> /^\s$/.test('\uFEFF')
true. (Punkt) passt zu allen Codeeinheiten (nicht Codepunkten!) außer Zeilenabschlüssen. Sehen Sie im nächsten Abschnitt, wie Sie jeden Codepunkt abgleichen./m: Im Mehrzeilenmodus passt die Assertion ^ am Anfang der Eingabe und nach Zeilenabschlüssen. Die Assertion $ passt vor Zeilenabschlüssen und am Ende der Eingabe. Im Nicht-Mehrzeilenmodus passen sie nur am Anfang bzw. am Ende der Eingabe.Andere wichtige Zeichenklassen haben Definitionen, die auf ASCII, nicht auf Unicode basieren
\d \D (Ziffern, Nicht-Ziffern): Eine Ziffer ist äquivalent zu [0-9].\w \W (Wortzeichen, Nicht-Wortzeichen): Ein Wortzeichen ist äquivalent zu [A-Za-z0-9_].
\b \B (an Wortgrenzen, innerhalb von Wörtern): Wörter sind Sequenzen von Wortzeichen ([A-Za-z0-9_]). Zum Beispiel im String 'über' sieht die Zeichenklassen-Escape \b das Zeichen b als Beginn eines Wortes
> /\bb/.test('über')
trueUm jede Codeeinheit abzugleichen, können Sie [\s\S] verwenden; sieheAtome: Allgemein.
Um jeden Codepunkt abzugleichen, müssen Sie verwenden:[20]
([\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])
Das vorherige Muster funktioniert wie folgt
([BMP code point]|[leading surrogate][trailing surrogate])
Da alle diese Bereiche disjunkt sind, passt das Muster korrekt auf Codepunkte in gut formatierten UTF-16-Zeichenketten.
Einige Bibliothekenhelfen bei der Handhabung von Unicode in JavaScript:
XRegExp ist eine Bibliothek für reguläre Ausdrücke, die ein offizielles Add-on zum Abgleichen von Unicode-Kategorien, Skripten, Blöcken und Eigenschaften über eine der folgenden drei Konstrukte hat
\p{...} \p{^...} \P{...}Zum Beispiel passt \p{Letter} auf Buchstaben in verschiedenen Alphabeten, während \p{^Letter} und \P{Letter} beide auf alle anderen Codepunkte passen. Kapitel 30 enthält einen kurzen Überblick über XRegExp.
Weitere Informationen zu Unicode finden Sie in Folgendem:
Informationen zur Unicode-Unterstützung in JavaScript finden Sie unter
Die folgenden Personen haben zu diesem Kapitel beigetragen: Mathias Bynens (@mathias), Anne van Kesteren (@annevk) und Calvin Metcalf (@CWMma).