Unicode- und Emoji-Kodierung: Codepunkte bis Rendering

Unicode: Der Kodierungsstandard, der alle Zeichen vereint

Unicode weist jedem Zeichen fast aller Schriftsysteme der Welt eine eindeutige Nummer (Codepunkt) zu.

Konzept Beschreibung Beispiel
Codepunkt (Code Point) Eindeutige Nummer des Zeichens U+4E2D (中)
Codeebene Jeweils 65536 Codepunkte bilden eine Ebene BMP (Ebene 0)
BMP Basic Multilingual Plane, U+0000~U+FFFF Die meisten häufigen Zeichen
Ergänzungsebene U+10000~U+10FFFF Emoji, antike Schriften, seltene Zeichen

1. Die UTF-Kodierungsfamilie

Kodierung Bytelänge Kodierung von "中" Merkmale
UTF-8 1-4 Bytes E4 B8 AD Variabel, ASCII-kompatibel, Web-Standard
UTF-16 2 oder 4 Bytes 4E2D Variabel, interne JS-Nutzung
UTF-32 Fest 4 Bytes 00004E2D Fest, hoher Speicherverbrauch

UTF-8-Kodierungsregeln

Codepunktbereich Bytes Kodierungsvorlage
U+0000 ~ U+007F 1 0xxxxxxx
U+0080 ~ U+07FF 2 110xxxxx 10xxxxxx
U+0800 ~ U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
U+10000 ~ U+10FFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Kodierungsbeispiel

Zeichen: 中
Codepunkt: U+4E2D = 0100 1110 0010 1101

UTF-8 (3 Bytes):
  1110xxxx 10xxxxxx 10xxxxxx
  1110 0100 10 111000 10 101101
  = E4 B8 AD

UTF-16 (2 Bytes):
  4E2D

UTF-32 (4 Bytes):
  00004E2D

2. Unicode-Fallen in JavaScript

Falsche Zeichenfolgenlänge

'中'.length              // 1 ✅
'𠮷'.length             // 2 ❌ (Zeichen der Ergänzungsebene, Ersatzpaar)
'👨‍👩‍👧‍👦'.length           // 11 ❌ (Emoji-ZWJ-Sequenz)
'🏳️‍🌈'.length             // 6 ❌ (Flaggen-Emoji)

Ursache: JS verwendet UTF-16

Zeichen der Ergänzungsebene (Codepunkt > U+FFFF) erfordern Ersatzpaare (2 UTF-16-Codeeinheiten):

Zeichen: 𠮷 (U+20BB7)
UTF-16-Ersatzpaar: D842 DF87
JS: length = 2 (zwei Codeeinheiten)

Korrekte Verarbeitung

// Methode 1: Spread-Operator
[...'𠮷'].length           // 1 ✅
[...'👨‍👩‍👧‍👦'].length         // 1 ✅ (aber ZWJ-Sequenz als eins gezählt)

// Methode 2: Array.from
Array.from('𠮷').length    // 1 ✅

// Methode 3: for...of
for (const char of '𠮷👨‍👩‍👧‍👦') {
  console.log(char);  // zeichenweise Iteration
}

Codepunktoperationen

// Codepunkt abrufen
'中'.codePointAt(0)        // 20013 (0x4E2D)
'𠮷'.codePointAt(0)        // 134047 (0x20BB7)

// Zeichen aus Codepunkt erstellen
String.fromCodePoint(0x4E2D)  // '中'
String.fromCodePoint(0x20BB7) // '𠮷'

// Hinweis: charCodeAt kann die Ergänzungsebene nicht verarbeiten
'𠮷'.charCodeAt(0)         // 55362 (nur das erste Ersatzzeichen)

3. Tiefenanalyse der Emoji-Kodierung

Vier Emoji-Typen

Typ Beispiel Codepunkt Länge
Basis-Emoji 😀 U+1F600 1 (Codepunkt)
Emoji mit Modifikator 👩🏽 U+1F469 + U+1F3FD 2 (Codepunkte)
ZWJ-Sequenz 👨‍👩‍👧‍👦 Mehrere Codepunkte + ZWJ 7 (Codepunkte)
Flaggen-Emoji 🇨🇳 U+1F1E8 + U+1F1F3 2 (Codepunkte)

Zero-Width-Joiner (ZWJ)

ZWJ (U+200D) verbindet mehrere Emoji zu einem zusammengesetzten Emoji:

👨 (U+1F468) + ZWJ (U+200D) + 👩 (U+1F469) + ZWJ (U+200D) + 👧 (U+1F467) + ZWJ (U+200D) + 👦 (U+1F466)
= 👨‍👩‍👧‍👦 (Vier-Personen-Familie)

Hautfarbenmodifikatoren

Hautfarbenmodifikatoren (U+1F3FB ~ U+1F3FF) ändern die Hautfarbe des Emoji:

👩 (U+1F469) + 🏽 (U+1F3FD) = 👩🏽 (Frau mit mittlerer Hautfarbe)
Modifikator Codepunkt Hautfarbe
U+1F3FB 🏻 Helle Hautfarbe
U+1F3FC 🏼 Mittelhelle Hautfarbe
U+1F3FD 🏽 Mittlere Hautfarbe
U+1F3FE 🏾 Mitteldunkle Hautfarbe
U+1F3FF 🏿 Dunkle Hautfarbe

Flaggen-Emoji

Flaggen bestehen aus zwei regionalen Indikatorsymbolen (ISO 3166-1 alpha-2):

🇨 (U+1F1E8) + 🇳 (U+1F1F3) = 🇨🇳 (China)
🇺 (U+1F1FA) + 🇸 (U+1F1F8) = 🇺🇸 (USA)
🇯 (U+1F1EF) + 🇵 (U+1F1F5) = 🇯🇵 (Japan)

4. Variantenselektoren

VS16 (U+FE0F) wandelt die Textdarstellung in Emoji-Darstellung um:

❤ (U+2764)           → Textdarstellung: ❤ (schwarzes Herz)
❤️ (U+2764 + U+FE0F) → Emoji-Darstellung: ❤️ (rotes Herz)
Zeichen Ohne VS16 Mit VS16
☕ ☕ (Text) ☕️ (Emoji)
⚡ ⚡ (Text) ⚡️ (Emoji)
❤ ❤ (Text) ❤️ (Emoji)

5. Verwendung von Tool-Bibliotheken zur Unicode-Verarbeitung

Unicode-Kodierung/Dekodierung

  1. Öffnen Sie das Unicode-Kodierungs-/Dekodierungstool
  2. Geben Sie Text oder Codepunkt ein
  3. Prüfen Sie die Konvertierungsergebnisse:
    • Text → Unicode-Escapesequenz (\u4E2D)
    • Codepunkt → Zeichen
    • UTF-8/16/32-Bytesequenz

Emoji-Kodierung

  1. Öffnen Sie das Emoji-Kodierungstool
  2. Geben Sie ein Emoji ein
  3. Prüfen Sie die vollständigen Kodierungsinformationen:
    • Codepunktsequenz
    • UTF-8-Bytes
    • ZWJ/Modifikator-Zerlegung
    • CLDR-Kurzname

6. Häufige Fallstricke und Lösungen

Fallstrick 1: Zeichenfolgenabschneidung

// Falsch: Abschneiden kann Ersatzpaare trennen
text.substring(0, 10)  // kann ungültige Zeichen erzeugen

// Richtig: nach Codepunkt abschneiden
function sliceByCodePoint(str, start, end) {
  const chars = [...str];
  return chars.slice(start, end).join('');
}

Fallstrick 2: Zeichenfolgenumkehr

// Falsch: Umkehr zerstört kombinierte Zeichen
'👨‍👩‍👧‍👦'.split('').reverse().join('')  // unleserlich

// Richtig: nach Codepunkt umkehren
[...'👨‍👩‍👧‍👦'].reverse().join('')  // ✅

Fallstrick 3: Regex-Übereinstimmung

// Falsch: . stimmt nicht mit Zeichen der Ergänzungsebene überein
/^.$/.test('𠮷')  // false

// Richtig: u-Flag verwenden
/^.$/u.test('𠮷')  // true

Fallstrick 4: Sortierung

// Standardsortierung nach UTF-16-Codeeinheiten
['中', '𠮷', 'a'].sort()  // möglicherweise nicht wie erwartet

// Richtig: nach Codepunkt sortieren
['中', '𠮷', 'a'].sort((a, b) =>
  a.codePointAt(0) - b.codePointAt(0)
)

7. Praktische APIs

// Normalisierung (Umgang mit kombinierter Zeichenäquivalenz)
'café'.normalize('NFC')   // café (kombiniert)
'café'.normalize('NFD')   // café (zerlegt)

// Emoji erkennen
function isEmoji(char) {
  const code = char.codePointAt(0);
  return (code >= 0x1F600 && code <= 0x1F64F) ||  // Emoticons
         (code >= 0x1F300 && code <= 0x1F5FF) ||  // Verschiedene Symbole
         (code >= 0x1F680 && code <= 0x1F6FF) ||  // Transport
         (code >= 0x1F900 && code <= 0x1F9FF);    // Ergänzend
}

// Tatsächliche Zeichenlänge abrufen
function graphemeLength(str) {
  const segmenter = new Intl.Segmenter('de', { granularity: 'grapheme' });
  return [...segmenter.segment(str)].length;
}

graphemeLength('👨‍👩‍👧‍👦')  // 1 ✅
graphemeLength('🏳️‍🌈')    // 1 ✅
#Unicode#Emoji#UTF-8#字符编码#码点