Emoji für Entwickler
Die meisten Emoji-Bugs gehen auf eine einzige Diskrepanz zurück: Dein Code zählt etwas anderes als das, was der Leser sieht. Ein Familien-Emoji ist ein Bild, sieben Code Points, 11 JavaScript-Zeichen und 25 Bytes. Wir haben die üblichen Regexes, Segmentierer und Längenprüfungen auf alle 3,963 Emoji aus Unicodes eigener Liste angewendet. Diese Seite zeigt, was sie tatsächlich erfassen, damit du die passende Methode wählst, bevor dir ein Bugreport verrät, welche du gewählt hast.
Ein Emoji, in jeder Sprache eine andere Länge
Jede Zelle zeigt, was der Ausdruck für das Emoji oben in der Spalte zurückgibt. Die Werte fallen in vier Gruppen: UTF-16-Einheiten, Code Points, UTF-8-Bytes und Grapheme (das, was ein Mensch zählt). Die Graphem-Spalte berechnet Intl.Segmenter auf diesem Server; eine Laufzeit mit älteren Unicode-Daten kann für die neuesten Emoji also mehr liefern.
| Ausdruck | Zählt | 😀 | ❤️ | 👍🏽 | 🇯🇵 | 👩💻 | 👨👩👧👦 | 🧑🏻❤️💋🧑🏼 |
|---|---|---|---|---|---|---|---|---|
JavaScripts.length | UTF-16-Einheiten | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
JavaScript[...s].length | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
JavaScriptIntl.Segmenter | Grapheme | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Pythonlen(s) | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Pythonlen(s.encode('utf-8')) | UTF-8-Bytes | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Javas.length() | UTF-16-Einheiten | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
Javas.codePointCount(0, s.length()) | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
C#s.Length | UTF-16-Einheiten | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
C# (.NET 5+)new StringInfo(s).LengthInTextElements | Grapheme | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Golen(s) | UTF-8-Bytes | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Goutf8.RuneCountInString(s) | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rusts.len() | UTF-8-Bytes | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
Rusts.chars().count() | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Swifts.count | Grapheme | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Swifts.unicodeScalars.count | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rubys.length | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
Rubys.grapheme_clusters.length | Grapheme | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
PHPstrlen($s) | UTF-8-Bytes | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
PHPmb_strlen($s) | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
PHPgrapheme_strlen($s) | Grapheme | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
MySQLCHAR_LENGTH(s) | Code Points | 1 | 2 | 2 | 2 | 3 | 7 | 10 |
MySQLLENGTH(s) | UTF-8-Bytes | 4 | 6 | 8 | 8 | 11 | 25 | 35 |
SQL ServerLEN(s) on nvarchar | UTF-16-Einheiten | 2 | 2 | 4 | 4 | 5 | 11 | 15 |
Was ein naiver Schnitt mit einem Emoji macht
Hier ist s.slice(0, n) auf die Familie 👨👩👧👦 angewendet, für jedes n. Die meisten Schnitte scheitern nicht lautstark. Sie liefern eine andere, kleinere Familie, und genau so landet diese Art Bug unbemerkt in Produktion.
| Schnitt bei n | Was übrig bleibt | Verbleibende Code Points |
|---|---|---|
| s.slice(0, 1) | �ein halbes Surrogatpaar (erscheint als �) | 0 |
| s.slice(0, 2) | 👨 | 1 |
| s.slice(0, 3) | 👨 | 2 |
| s.slice(0, 4) | 👨�ein halbes Surrogatpaar (erscheint als �) | 2 |
| s.slice(0, 5) | 👨👩 | 3 |
| s.slice(0, 6) | 👨👩 | 4 |
| s.slice(0, 7) | 👨👩�ein halbes Surrogatpaar (erscheint als �) | 4 |
| s.slice(0, 8) | 👨👩👧 | 5 |
| s.slice(0, 9) | 👨👩👧 | 6 |
| s.slice(0, 10) | 👨👩👧�ein halbes Surrogatpaar (erscheint als �) | 6 |
| s.slice(0, 11) | 👨👩👧👦 | 7 |
Die Flagge, die das Land wechselt
Regionale Indikatorbuchstaben bilden ab dem Anfang des Strings Paare. Entferne einen Code Point vorne aus 🇺🇸🇯🇵, und die übrigen Buchstaben paaren sich anders: 🇸🇯🇵. Kein Fehler, nur ein anderes Land.
🇺🇸🇯🇵 US + JP → 🇸🇯 SJ (Svalbard & Jan Mayen) + 🇵
Welche Emoji-Regex was erkennt
Getestet am 2026-10-20 gegen alle 3,963 fully-qualified Emoji, unter Node 25.2.1 mit den Daten von Unicode 17.0. Ein Muster zählt nur dann als Treffer, wenn es das gesamte Emoji erfasst.
| Muster | Treffer | Was es übersieht |
|---|---|---|
| /^\p{RGI_Emoji}$/v | 3,944 / 3,963 | Jedes Emoji, das neuer ist als die Unicode-Daten der Engine: Emoji 18.0 (19) |
| Intl.Segmenter | 3,963 / 3,963 | Nichts auf dieser Laufzeit |
| /\p{Extended_Pictographic}/u | 3,692 / 3,963 | 259 Flaggen und 12 Keycaps, die überhaupt keinen piktografischen Code Point enthalten |
| /^\p{Extended_Pictographic}$/u | 1,193 / 3,963 | Alles, was aus mehr als einem Code Point besteht: Hauttöne, Flaggen, Keycaps, ZWJ-Sequenzen und Emoji mit Stil-Selektor |
Und die, die du meiden solltest: \p{Emoji} trifft auch # * 0 1 2 3 4 5 6 7 8 9 © ®. Wer damit Emoji entfernt, löscht jede Ziffer im Text.
Emoji entfernen: was jeder Ansatz zurücklässt
Beide Zeilen unten waren ursprünglich derselbe Text. Die Reste sind in den meisten Schriftarten unsichtbar, und genau deshalb machen sie später Ärger: bei der Suche, bei der Deduplizierung und bei Längenlimits.
Great 👍🏽 job ❤️ 👩💻 🇯🇵 #️⃣1
| Ansatz | Ergebnis | Übrige Code Points |
|---|---|---|
| \p{Extended_Pictographic} entfernen | Great 🏽 job ️ 🇯🇵 #️⃣1 | U+1F3FD U+FE0F U+200D U+1F1EF U+1F1F5 U+FE0F U+20E3 |
| \p{RGI_Emoji} entfernen | Great job 1 | keine |
Wie viel Platz Emoji in einer Datenbank belegen
UTF-8-Bytes pro Emoji über alle 3,963. 30% passen in vier Bytes oder weniger; das längste braucht 35. Ist eine Spalte in Bytes statt in Zeichen begrenzt, dimensioniere sie nach dieser Tabelle, nicht danach, wie der Text aussieht.
| UTF-8-Bytes | Emoji, die passen | Anteil |
|---|---|---|
| ≤ 4 | 1,193 | 30% |
| ≤ 8 | 2,346 | 59% |
| ≤ 11 | 2,424 | 61% |
| ≤ 17 | 3,424 | 86% |
| ≤ 28 | 3,868 | 98% |
| ≤ 35 | 3,963 | 100% |
🧑🏻❤️💋🧑🏼 U+1F9D1 U+1F3FB U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F9D1 U+1F3FC
Wähle die Zählung, die zu deinem Limit passt
Es gibt nicht die eine richtige Länge, nur die, die zur durchgesetzten Regel passt. Eine in Bytes begrenzte Datenbankspalte braucht UTF-8-Bytes. Ein Textfeld, das einem Menschen 50 Zeichen verspricht, braucht Grapheme, sonst erfährt jemand, der drei Flaggen tippt, er habe 12 verbraucht. SQL Server tanzt aus der Reihe: nvarchar(n) zählt UTF-16-Einheiten, also belegt 😀 zwei Zeichen eines nvarchar, aber nur eines in einem varchar von MySQL oder PostgreSQL, die Code Points zählen. Leg fest, welche der vier du meinst, schreib es in den Variablennamen, und der Rest ergibt sich.
Kürze an Graphemgrenzen, nicht an Indizes
Jeder Schnitt per Index kann mitten in einem Emoji landen. Bei UTF-16 ist der schlimmste Fall ein halbes Surrogatpaar, das die meisten Renderer als Kästchen mit Fragezeichen anzeigen und das manche JSON-Encoder schlicht ablehnen. Bei Code Points bricht sichtbar nichts, und das ist schlimmer: Die Familie verliert ein Kind, ein Hautton fällt ab und erscheint als braunes Quadrat, oder eine Flagge wird zu zwei Buchstaben. Die Lösung: erst segmentieren, dann eine ganze Zahl von Graphemen abschneiden. Intl.Segmenter steckt in jedem großen Browser, seit Firefox 125 es im April 2024 ausgeliefert hat, und in Node schon länger. Die alte Ausrede für einen handgeschriebenen Splitter gilt also nicht mehr.
Snippets zum Kopieren
Kurz und, wo die Sprache es erlaubt, ohne Abhängigkeiten. Jedes löst einen Fall aus den Tabellen oben.
Zählen, was der Leser sieht (JavaScript)
const seg = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
const visibleLength = (s) => [...seg.segment(s)].length;
visibleLength('👨👩👧👦 ok'); // 4, while '👨👩👧👦 ok'.length is 14Kürzen, ohne ein Emoji zu zerteilen (JavaScript)
function truncate(s, max, ellipsis = '…') {
const parts = [...seg.segment(s)].map((x) => x.segment);
return parts.length <= max ? s : parts.slice(0, max - 1).join('') + ellipsis;
}Alle Emoji finden, inklusive Flaggen und Keycaps (JavaScript)
// ES2024 'v' flag: Chrome 112, Safari 17, Firefox 116, Node 20
const emoji = /\p{RGI_Emoji}/gv;
'Go 🇯🇵 #️⃣1 👍🏽'.match(emoji); // ['🇯🇵', '#️⃣', '👍🏽']Dasselbe in Python, mit dem Modul regex
import regex # pip install regex; the built-in re has no \X
graphemes = regex.findall(r'\X', '👨👩👧👦 ok')
len(graphemes) # 4, while len('👨👩👧👦 ok') is 10Spalten, die jedes Emoji aufnehmen
-- MySQL: utf8mb4 on the column AND the connection
CREATE TABLE posts (body VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci);
SET NAMES utf8mb4;
-- PostgreSQL: any UTF8 database already stores every emoji
-- SQL Server: use nvarchar, and remember LEN() counts UTF-16 unitsWarum keine Regex je fertig ist
Jede Emoji-Eigenschaft einer Regex-Engine stammt aus Unicode-Daten, die in diese Engine kompiliert sind. Ein Muster ist also nur so aktuell wie die Laufzeit, die es ausführt. Unser eigener Test zeigt das: \p{RGI_Emoji} traf 3,944 von 3,963, weil die 19 neuesten Sequenzen noch nicht in den Unicode-17.0-Tabellen von Node 25.2.1 stehen. Derselbe Code erkennt sie nach einem Laufzeit-Upgrade, und wer einen älteren Browser nutzt, wird sie weiterhin verpassen. Muss eine Prüfung neue Emoji ab dem ersten Tag akzeptieren, prüfe die Struktur (Extended_Pictographic plus Modifikatoren, Joiner und Selektoren) oder Grapheme, und nutze die Eigenschaft nur dort, wo ein falsch negatives Ergebnis harmlos ist.
Dasselbe Emoji lässt sich auf drei Arten speichern
Unicode führt 3,963 fully-qualified Emoji, dazu 1,029 minimally-qualified und 243 unqualified Formen derselben Bilder, meist die Varianten ohne den Stil-Selektor U+FE0F. ❤ und ❤️ sehen in vielen Apps gleich aus, sind aber verschiedene Strings. Eine Eindeutigkeitsprüfung, ein Reaktionszähler oder ein Suchindex behandelt sie daher als zwei verschiedene Dinge. Unicode-Normalisierung hilft hier nicht: NFC und NFKC lassen Variantenselektoren unangetastet. Wenn du Emoji vergleichst oder deduplizierst, leg dich auf eine Form fest (fully-qualified ist die sichere Wahl) und konvertiere bei der Eingabe anhand der Qualifizierungsliste, statt jedes U+FE0F zu entfernen, was auch Keycaps wie 1️⃣ kaputt machen würde.
Emoji-Unicode-KonverterAlle ZWJ-Sequenzen mit ihrer GrößeZeichenzähler, der Emoji richtig zähltEmoji-Glossar
Was Entwickler über Emoji fragen
Warum hat ein Emoji in JavaScript die Länge 2?
JavaScript-Strings sind UTF-16, und jedes Zeichen oberhalb von U+FFFF belegt zwei 16-Bit-Einheiten, ein Surrogatpaar. Fast alle Emoji liegen oberhalb von U+FFFF, deshalb hat selbst ein einfaches 😀 eine .length von 2. Nutze [...str].length für Code Points oder Intl.Segmenter für das, was der Leser sieht.
Was ist die beste Regex für Emoji?
In modernem JavaScript erkennt /\p{RGI_Emoji}/v vollständige Emoji-Sequenzen samt Flaggen und Keycaps, aber nur bis zur Unicode-Version, die die Engine kennt. \p{Extended_Pictographic} übersieht Flaggen und Keycaps, und \p{Emoji} trifft fälschlich Ziffern, # und *.
Wie zähle ich ein Emoji als ein Zeichen?
Zähle Graphem-Cluster. In JavaScript mit Intl.Segmenter und granularity grapheme; in Swift erledigt das String.count bereits; in Python mit \X aus dem Drittanbieter-Modul regex; in PHP mit grapheme_strlen aus der Erweiterung intl.
Wie viele Bytes brauche ich, um ein Emoji zu speichern?
In UTF-8 zwischen 3 und 35 Bytes. Ein Emoji aus einem einzigen Code Point oberhalb von U+FFFF belegt 4. Hauttöne, Flaggen und verbundene Sequenzen summieren sich: In unserem Test passen 59% aller Emoji in 8 Bytes, und das längste, ein Kuss mit zwei Hauttönen, belegt 35.
Warum wird mein Emoji in der Datenbank zu ????
Die Spalte oder die Verbindung nutzt einen Zeichensatz, der keine Vier-Byte-Zeichen speichern kann, meist das alte utf8 von MySQL. Stelle sowohl die Tabelle als auch die Verbindung auf utf8mb4 um. Unsere Seite zum Unicode-Konverter zeigt die genaue ALTER TABLE-Anweisung.
