A code point is the unique number Unicode assigns to each character. For あ it is U+3042. The rules for converting that number into an actual sequence of bytes are UTF-8 and UTF-16, and the two are separate concepts. This article sorts out what a code point means, how UTF-8 produces 1-4 bytes, and why emoji become surrogate pairs, along with ways to verify it yourself.
1. What a code point is
Unicode is an enormous character set that assigns a serial number to every character in the world. The number that corresponds to each character is its code point, conventionally written as U+ followed by a hexadecimal number.
A= U+0041 (65 in decimal)あ= U+3042 (12354 in decimal)漢= U+6F22😀= U+1F600 (128512 in decimal)
So far this only "decides a number"; the form in which it is stored on a computer (the bytes) is not yet determined. That is what an encoding scheme handles.
2. UTF-8 - encoding into 1-4 bytes
UTF-8 is a scheme that represents a character in 1 to 4 bytes depending on the size of the code point. It is compatible with ASCII and is the most widely used encoding on the web.
| Range | UTF-8 byte count | Example |
|---|---|---|
| U+0000 to U+007F | 1 byte | A → 41 |
| U+0080 to U+07FF | 2 bytes | é → C3 A9 |
| U+0800 to U+FFFF | 3 bytes | あ → E3 81 82 |
| U+10000 to U+10FFFF | 4 bytes | 😀 → F0 9F 98 80 |
In other words, the reason "one Japanese character is 3 bytes" holds is that many characters fall into this 3-byte range. This is why the character count and the byte count do not match, and it is something you need to keep in mind when designing things like database column widths.
3. UTF-16 and \uXXXX
UTF-16 is a scheme that represents characters in 16-bit (2-byte) units, and it is the one JavaScript strings adopt internally. Characters at U+FFFF or below are 1 unit, and characters beyond that are represented by 2 units called a surrogate pair. The \uXXXX you often see in source code and JSON strings is one of these UTF-16 units written in hexadecimal.
あ(U+3042) →あ(1 unit)😀(U+1F600) →😀(2 units, a high and a low)
4. Why emoji become surrogate pairs
UTF-16 originally only anticipated the range representable in 16 bits (up to U+FFFF). To represent characters beyond that, a surrogate pair is the mechanism that combines 2 units from a reserved range (D800 to DFFF) to represent a single code point. 😀 is represented by the pair of a high D83D and a low DE00.
As a result, JavaScript's "😀".length is 2. Even though the code point is one, in UTF-16 units it is two.
5. How to try it yourself (JavaScript)
In the console or in Node.js, you can check the code point, the UTF-8 bytes, and the UTF-16 units individually.
const ch = "😀";
// Code point (U+)
console.log(ch.codePointAt(0).toString(16).toUpperCase()); // 1F600
// UTF-8 byte sequence
console.log([...new TextEncoder().encode(ch)]
.map(b => b.toString(16).toUpperCase())); // ["F0","9F","98","80"]
// UTF-16 units (\uXXXX)
console.log(ch.length); // 2 (surrogate pair)
console.log([...ch].length); // 1 (counted by code point)
When you want to check multiple characters together in a table, paste your text into the code point checker below. It lists U+, decimal, UTF-8, and UTF-16 for each character.
Free Tool Look it up with the Code Point Checker Enter your text and it lists each character's U+ code point, decimal, UTF-8 bytes, and UTF-16 (\uXXXX). Everything runs entirely in your browser.Frequently Asked Questions (FAQ)
Do code point and character encoding mean the same thing?
Strictly speaking, no. A code point is the abstract number Unicode assigns to each character (for example, あ is U+3042), while UTF-8 and UTF-16 are encoding schemes, the rules for converting that number into an actual sequence of bytes. In everyday conversation the two are often lumped together as character encoding, but it becomes easier to understand if you separate the number itself from the scheme that encodes it into bytes.
What decides how many bytes a single character takes?
It is decided by the encoding scheme and the size of the code point. In UTF-8, U+0000 to U+007F (ASCII) take 1 byte, most Japanese characters take 3 bytes, and emoji and the like take 4 bytes. In UTF-16, characters at U+FFFF or below take 2 bytes, and characters beyond that take 4 bytes (a surrogate pair). The same character can take a different number of bytes under a different scheme.
Why does JavaScript's length count an emoji as 2?
Because JavaScript strings are managed in UTF-16, and length returns the count of 16-bit units. An emoji beyond U+FFFF becomes 2 units as a surrogate pair, so its length is 2. When you want to count by code point, use for...of, Array.from, or [...str] to treat it as a single character.