Guides Development

How Unicode and UTF-8 Work

Code points, planes and encodings explained: how UTF-8 stores characters in 1 to 4 bytes (with a verified table), what UTF-16 surrogate pairs are, why é can be one or two code points, and how to avoid mojibake.

Last reviewed:

AdSense Placeholder
Slot: header_reference_page
On this page

Unicode gives every character a number called a code point, written U+0041 for A. There are 1,114,112 possible code points, arranged in 17 planes of 65,536. An encoding such as UTF-8 or UTF-16 turns code points into bytes. Look characters up with the Unicode Character Inspector and clean text with the Unicode Normalizer; the dictionary entry is Unicode.

UTF-8 in one table

UTF-8 is backward compatible with ASCII (the first 128 code points are one byte, identical to ASCII), self-synchronising (you can find a character boundary from any byte) and the default for the web. UTF-16 uses 2 bytes for most characters and a surrogate pair of two 2-byte units for code points above U+FFFF, such as emoji.

Code point range Bytes Bit pattern
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

Examples, verified

Character Code point UTF-8 (hex) UTF-16 (hex)
A U+0041 41 0041
é U+00E9 c3 a9 00e9
€ U+20AC e2 82 ac 20ac
😀 U+1F600 f0 9f 98 80 d83d de00

One character, several code points

  • é can be one code point (U+00E9) or two: e plus a combining acute accent (U+0301). The text looks the same but its length is 1 or 2, and a plain comparison fails. Normalisation converts both to one form: NFC composes, NFD decomposes; NFKC and NFKD also fold compatibility characters (fi becomes fi, ² becomes 2).
  • What people see as one character (a grapheme cluster) can be many code points: the family emoji is 5 code points joined by zero-width joiners and takes 18 bytes in UTF-8.
  • String length depends on the unit: bytes, UTF-16 units, code points or graphemes can all differ for the same text.

Mojibake and other traps

  • Mojibake: UTF-8 bytes read as Latin-1 turn naïve into naïve. Always declare the encoding (<meta charset="utf-8">, an HTTP header, or your editor setting).
  • Invisible characters (zero-width spaces, bidirectional controls) can hide in copied text and in identifiers; find them with the Invisible Character Detector.
  • Lookalikes: Cyrillic а is not Latin a. Domain names handle this with Punycode, see Punycode.
  • A UTF-8 byte order mark (EF BB BF) at the start of a file is allowed but usually unwanted.

Try these tools

See also

  • Glossary Unicode
    Unicode is the universal standard that gives every character in the world's writing systems, plus symbols and emoji.
  • Glossary UTF-8
    UTF-8 is the dominant Unicode encoding, writing each character as one to four bytes and staying identical to ASCII for the first 128.
  • Glossary ASCII
    ASCII is a 7-bit character encoding that assigns numbers 0 to 127 to English letters, digits, punctuation and control codes.
  • Glossary Punycode
    Punycode is the encoding that lets domain names with non-ASCII characters be stored in the ASCII-only DNS, marked by the prefix xn--.
  • Glossary Unicode Normalization
    Unicode normalization converts text that can be written in more than one way, such as an accented letter.
  • Cheat sheet ASCII Table Cheat Sheet
    All 95 printable ASCII characters with decimal and hex codes, the control characters you will meet.
  • Cheat sheet HTML Entities Cheat Sheet
    The HTML entities you actually use, with name, decimal code and meaning, which five characters to escape and how entities are decoded.

Frequently Asked Questions

The file is UTF-8 but was read as Latin-1 (or Windows-1252). Each byte was shown as its own character. Reopen it, choosing UTF-8 as the encoding.

AdSense Placeholder
Slot: footer_leaderboard