</>DevTools

U+Unicode Converter

Convert between Unicode escapes and text

Working with Unicode Escapes and Code Points

Notation like \uD55C writes a Unicode code point using only ASCII. It's useful for keeping source files independent of any particular encoding, and for placing non-ASCII text where only ASCII is safe. The thing everyone trips over is that characters with large code points — emoji, most notably — cannot be written as a single \u escape.

Code points, code units, and surrogate pairs

Unicode assigns every character a number, its code point: '한' is U+D55C, 😀 is U+1F600. The complication is that JavaScript and Java strings are UTF-16 based, and UTF-16's unit — the code unit — is 16 bits wide, which only reaches U+FFFF.

Characters above U+FFFF are therefore encoded as a pair of 16-bit units, called a surrogate pair, with the leading unit in U+D800–U+DBFF and the trailing one in U+DC00–U+DFFF. So 😀 is written \uD83D\uDE00. Since ES6 you can instead write the code point directly as \u{1F600}, which is far clearer.

CharacterCode point\u form (UTF-16)ES6 formUTF-8 bytes
AU+0041\u0041\u{41}41
éU+00E9\u00E9\u{E9}C3 A9
U+D55C\uD55C\u{D55C}ED 95 9C
😀U+1F600\uD83D\uDE00\u{1F600}F0 9F 98 80

How to use it

  1. Enter text to get its Unicode escape representation.
  2. Or paste a \uXXXX string to convert it back into readable characters.
  3. Copy the result straight into source code or a JSON value.
  4. If an emoji comes out as two escapes, that's a surrogate pair and is expected.

Why string length surprises you

'😀'.length is 2, not 1, because length counts UTF-16 code units rather than characters. Any character limit applied to input containing emoji will therefore behave differently from what users perceive.

It goes further: many things people read as one character are several code points. The family emoji 👨‍👩‍👧 is three person emoji joined by zero-width joiners (U+200D), flags are pairs of regional indicator symbols, and decomposed Hangul spells one syllable out of several jamo.

Length depends on what you count
const s = "👨‍👩‍👧";

s.length                              // 8  (UTF-16 code units)
[...s].length                         // 5  (code points)
new TextEncoder().encode(s).length    // 18 (UTF-8 bytes)

// count what users perceive as characters
const seg = new Intl.Segmenter("en", { granularity: "grapheme" });
[...seg.segment(s)].length            // 1

Why normalization (NFC/NFD) matters

Some characters have more than one valid Unicode representation. 'é' can be the single code point U+00E9, or 'e' (U+0065) followed by a combining acute accent (U+0301). They look identical but compare as unequal with ===.

The canonical real-world case is macOS, whose filesystem stores names in NFD (decomposed) form — which is why zipping Korean filenames on a Mac and extracting them on Windows can show the jamo split apart. When comparing or storing strings, normalize to one form with String.prototype.normalize("NFC").

Strings that look identical but aren't
const a = "가";                    // NFC: U+AC00
const b = "\u1100\u1161";          // NFD: ㄱ + ㅏ

a === b                            // false
a.normalize("NFC") === b.normalize("NFC")  // true

Common uses

  • Putting non-ASCII text into ASCII-only config formats like Java .properties files
  • Escaping non-ASCII literals so source files don't depend on an encoding
  • Restoring readable text from an API response that arrived as \uXXXX escapes
  • Revealing invisible characters such as zero-width spaces and unusual space variants
  • Checking an emoji's real code points before deciding how to store it in a database

Why emoji vanish in your database

MySQL's utf8 charset, despite the name, stores at most 3 bytes per code point, so 4-byte emoji get truncated or rejected. To store emoji you need charset utf8mb4 with a collation like utf8mb4_unicode_ci or utf8mb4_0900_ai_ci — and you must set the connection charset too, since converting only the table while leaving the connection alone still corrupts the data.

Frequently Asked Questions

What's the difference between \uXXXX and \u{XXXXX}?
\uXXXX specifies one 16-bit code unit, so it only reaches U+FFFF and anything above needs two escapes forming a surrogate pair. The ES6 form \u{...} takes a code point directly, so a single \u{1F600} expresses an emoji. On modern JavaScript runtimes the latter is much easier to read.
Can I put non-ASCII text directly in JSON?
Yes. The JSON spec defaults to UTF-8, so literal non-ASCII characters are valid — which is why JSON.stringify doesn't escape them. Some servers and legacy libraries only handle ASCII reliably, and \uXXXX escapes exist for those environments. Both forms parse to exactly the same value.
What are zero-width characters?
Characters with no visible width, such as U+200B (zero width space), U+200D (ZWJ), and U+FEFF (BOM). They sneak in via copy-paste from web pages and cause string comparisons to fail or regexes not to match. Escaping the text with this tool makes them visible.
Why is a single emoji several code points?
Unicode builds new representations by composition. Skin-tone variants are a base emoji plus a modifier, family emoji are person emoji joined with ZWJ, and flags are pairs of regional indicators. That's also why some apps need several backspaces to delete one emoji.
Should I strip the BOM?
In UTF-8, usually yes. UTF-8 has a fixed byte order so the BOM serves no purpose, and leaving it at the start of a file causes JSON parse errors, shell scripts that won't run, and stray whitespace before PHP output. In UTF-16 the BOM genuinely signals byte order, so don't remove it there.
Why shouldn't I count characters with length?
Because length counts UTF-16 code units, so one emoji counts as 2 or more. To count what users perceive as characters, Intl.Segmenter with grapheme granularity is the accurate approach; for code points, [...str].length is enough.

💡 Note: If a string comparison fails for no apparent reason, suspect mismatched normalization forms (NFC vs NFD) or a hidden zero-width character. Escape both sides and compare the code points directly.

🔗Related Tools🔄 Text / Data