Unicode Escape Converter
Convert text to \u0041-style Unicode escapes and back
Unicode Escape Converter
Working…
0.0
It hasn't frozen — the result will appear when the calculation finishes.
About Unicode Escape Converter
In the encode direction this tool writes each character as \uXXXX using UTF-16 code units. Anything outside the Basic Multilingual Plane — emoji, supplementary CJK — becomes a surrogate pair, so 😀 turns into the twelve characters \ud83d\ude00. In the decode direction it recognises four forms, \uXXXX, \u{1F600}, Python's \U0001F600 and \xXX, and leaves everything else untouched.
The escapes in JSON, JavaScript, Java and C# look identical, which makes it tempting to treat them as interchangeable. They are not: each language accepts different forms and processes them at a different stage. The sections below cover those differences and the mistakes they cause.
How 😀 becomes \uD83D\uDE00
\u takes exactly four hex digits, so it can only name code points up to U+FFFF. Higher code points are split the UTF-16 way. For U+1F600, subtract 0x10000 to get 0xF600, a 20-bit value. Its top ten bits (0x3D) are added to 0xD800 to make the high surrogate D83D; its bottom ten bits (0x200) are added to 0xDC00 to make the low surrogate DE00.
Unicode reserves the whole D800–DFFF range for this purpose and never assigns characters there. A string containing \uD83D on its own is therefore broken — a lone surrogate. Encoding it to UTF-8 either throws or produces U+FFFD (�). When the decoder produces a lone surrogate it shows a warning with the count under the result, so check whether your input was cut in the middle of a pair. This happens often when a string is truncated with substring() at a fixed length.
The same emoji in six syntaxes
The decoder reads the first three (for Python, only the \U form) plus \xXX. The \N{NAME} form would need the whole Unicode name table, so it is not supported and is left as written.
- JSON, Java, C#, pre-2015 JavaScript: \uD83D\uDE00 — the surrogate pair is mandatory
- JavaScript since ES2015: \u{1F600} — not valid in JSON
- Python 3: \U0001F600 (capital U, eight digits) or \N{GRINNING FACE}
- CSS: \1F600 followed by a space to end the escape
- HTML: 😀 or 😀
- URLs: %F0%9F%98%80 — the UTF-8 bytes, percent-encoded
Why \xed\x95\x9c does not decode to 한
Print 'é'.encode() in Python and you get b'\xc3\xa9': two UTF-8 bytes. JavaScript's \xXX means something else — one character in the range U+0000–00FF. By default this tool follows JavaScript, so decoding \xc3\xa9 gives you é, the exact mojibake you see when UTF-8 text is read as Latin-1 or Windows-1252. Switch on “Read runs of \x as UTF-8 bytes” in the decode direction and each run of consecutive \x escapes is collected as bytes and decoded as UTF-8, giving é. Bytes that are not valid UTF-8 become U+FFFD.
This distinction matters when you copy escapes out of Python logs, C source or network dumps: if the escapes represent bytes, treat them as bytes.
The Java comment that breaks compilation
Java translates \uXXXX across the entire source file before tokenising it (Java Language Specification §3.3), not only inside string literals. Put \u000a inside a // comment and the compiler sees a real line break, so whatever follows is parsed as code. \u0022 inside a string literal likewise ends the string. Use \n and \" inside strings instead. JavaScript and JSON only interpret escapes inside string literals (and, in JavaScript, identifiers), so they do not have this trap.
When escaping is still worth it
UTF-8 is the default nearly everywhere now, but escapes still earn their keep: Java .properties files before Java 9 were read as ISO-8859-1; some build pipelines and older Windows tools still guess encodings; and in logs or code review an escape makes invisible or look-alike characters unmistakable — \u00a0 instead of a space, \u200b instead of nothing, \u0430 (Cyrillic а) instead of a Latin a.
With “Keep plain ASCII characters as-is” switched on, only printable ASCII (0x20–0x7E) stays literal. Tabs and line breaks are control characters, so they come out as \u0009 and \u000a.
Worked examples
Accent, Hangul and emoji together
- Input
é한😀- Output
\u00e9\ud55c\ud83d\ude00
é and 한 are in the BMP, so one escape each; 😀 needs a surrogate pair. The output is valid inside a JSON string.
Decoding ES2015 code-point escapes
- Input
\u{1F600} \u{E9}- Output
😀 é
Braces take one to six hex digits. Values above 10FFFF are left as written.
Byte escapes are not UTF-8
- Input
\xc3\xa9- Output
Default: é / UTF-8 bytes option: é
By default each \x is a Latin-1 character, so the two UTF-8 bytes of é become two separate characters — classic mojibake. The option reads them as bytes.
How to use it
- Enter plain text or an escaped string.
- Choose encode or decode.
- Toggle ASCII passthrough or uppercase hex (encode), or \x as UTF-8 bytes (decode), if needed.
- Copy the result.
Frequently asked questions
Why does one emoji become two \u escapes?
Characters above U+FFFF take two UTF-16 code units (a surrogate pair), and each \uXXXX can only hold one.
Can I use \u{1F600} in JSON?
No. RFC 8259 allows only \u with four hex digits, so characters outside the BMP must be written as a twelve-character surrogate pair — or simply included as raw UTF-8.
Does it decode Python's \U0001F600?
Yes, the eight-digit \U form is decoded. Named escapes such as \N{GRINNING FACE} are not supported and are left unchanged.
Is \u00E9 different from \u00e9?
No. Hex digits are case-insensitive in every language that uses these escapes.
Why do I get a box instead of an emoji after decoding?
Probably a lone surrogate: only half of the pair was in the input. The tool shows a warning when this happens.
Related guides
Sources
- ECMAScript Language Specification: String Literals
- RFC 8259: The JSON Data Interchange Format, Section 7 (Strings)
- Unicode FAQ: UTF-16 and surrogates
- Java Language Specification §3.3 Unicode Escapes
- Python documentation: String and Bytes literals
Last reviewed: