A little help goes a long way. Find a tool/

Reference FIELD NOTES ยท 4 MIN READ

Unicode and Code Points: Beyond ASCII

How Unicode numbers every character from U+0000 to U+10FFFF: planes and blocks, UTF-8 byte counts, combining marks, and why one emoji can count as two characters.

ASCII gave a number to 128 characters โ€” enough for English, not for the world. Unicode finishes the job: every character in every living and historic writing system, every symbol, and thousands of emoji each get their own number, called a code point. Once you can read code points, a lot of browser and programming oddities stop being mysterious and start being arithmetic.

From 128 characters to 1,114,112

ASCII assigns codes 0โ€“127: control characters at the bottom, then punctuation, digits, uppercase, lowercase (see How Text Encoding Works for the full story). It fits in 7 bits and covers exactly one script. Unicode's ambition is bigger: assign a unique code point to every character ever used. The address space runs from U+0000 to U+10FFFF โ€” that is 17 planes of 65,536 code points each, 1,114,112 slots in total. Not all are filled, and some are reserved, but the ceiling is fixed by the format itself.

The first plane, U+0000 to U+FFFF, is the Basic Multilingual Plane (BMP), and it holds most of what you read daily: Latin, Greek, Cyrillic, Arabic, Hebrew, the major Indian and Southeast Asian scripts, CJK ideographs, punctuation, currency symbols. Emoji and rare historic scripts live in the supplementary planes above U+FFFF โ€” the grinning face sits at U+1F600 in the Emoticons block.

Reading a code point

The U+ prefix marks a hexadecimal number, so U+1F600 is decimal 128512. A few landmarks show how the space is organized:

A   = U+0041  (decimal 65)      LATIN CAPITAL LETTER A      Basic Latin
รฉ   = U+00E9  (decimal 233)     LATIN SMALL LETTER E WITH ACUTE  Latin-1 Supp.
โ‚ฌ   = U+20AC  (decimal 8364)    EURO SIGN                   Currency Symbols
๐Ÿ˜€  = U+1F600 (decimal 128512)  GRINNING FACE               Emoticons

Each code point also carries an official name and belongs to a named block โ€” a contiguous range reserved for a script or purpose. These metadata fields are what make a lookup tool useful: they turn "some weird box" in your terminal into a precise, searchable identity. (For how hexadecimal works, see Number Base Systems Explained.)

Code points are not bytes: UTF-8

A code point is a number, not a storage format; encodings turn numbers into bytes. UTF-8, the web's standard, uses 1 byte for code points up to U+007F (that is why ASCII text is valid UTF-8 unchanged), 2 bytes up to U+07FF, 3 bytes up to U+FFFF, and 4 bytes beyond. Count the difference on two words:

cafรฉ :  4 code points  โ†’  5 UTF-8 bytes   (รฉ costs 2 bytes)
๐Ÿ˜€   :  1 code point    โ†’  4 UTF-8 bytes

This is why "length" has three honest answers: a string can be 4 characters, 4 code points, and 5 bytes at once. Databases measure bytes, editors measure glyphs, and specs often mean code points โ€” which answer a tool gives you matters.

Code points are not what you see

Unicode also splits one visible character into multiple code points when it is useful. Accented letters exist as single points โ€” รฉ = U+00E9 โ€” but also as a base letter plus a combining mark: e (U+0065) followed by U+0301 (COMBINING ACUTE ACCENT). Both render as รฉ; the first is 1 code point and 2 UTF-8 bytes, the second is 2 code points and 3 UTF-8 bytes. Same glyph, different bytes โ€” the two forms are canonically equivalent, and Unicode defines normalization forms (NFC composes, NFD decomposes) so comparisons can agree on one. The same logic extends to flag emoji and family emoji, which are sequences of several code points rendered as one image. A code point is what Unicode stores; a grapheme is what your eye sees, and they agree only most of the time.

Why one emoji can count as two characters

Here is the quirk that trips up real code. JavaScript strings predate Unicode's expansion, so they are sequences of UTF-16 code units โ€” 16-bit numbers. Code points above U+FFFF do not fit, so UTF-16 stores them as a surrogate pair: two units, one after the other. JavaScript's .length counts units, not points, so:

"๐Ÿ˜€".length          โ†’  2     (one surrogate pair, ONE code point)
[..."๐Ÿ˜€"].length      โ†’  1     (spread iterates code points)
"cafรฉ".length        โ†’  4     (all below U+FFFF โ€” no surprise)

You can watch both counting models in one tool. The Character Counter reports ๐Ÿ˜€ as total 2, unique 1: the total follows .length (2 UTF-16 units) while the frequency table iterates code points and sees a single character. Neither number is wrong โ€” they are counting different layers, and now you know which is which. The same split explains why slice() can cut an emoji in half and why regexes need the u flag to match one whole emoji.

Try it yourself

Type รฉ, โ‚ฌ and ๐Ÿ˜€ into the Unicode Lookup and read back each code point, decimal value, official name, block and plane โ€” then paste ė (letter plus combining accent) and see it decompose into two code points. Browse the first 128 rows in the ASCII Table and notice they are exactly Unicode's U+0000โ€“U+007F block: ASCII did not go away, it became the foundation floor. Finally, count cafรฉ and a lone emoji in the Character Counter and check the numbers against the tables in this article.

Frequently asked questions

How many characters does Unicode define?
The address space holds 1,114,112 code points (17 planes of 65,536 each), of which a bit over 150,000 are assigned characters today. Large ranges remain unassigned or reserved โ€” room for scripts and symbols not yet encoded.
Why does "๐Ÿ˜€".length return 2 in JavaScript?
JavaScript strings are sequences of UTF-16 code units. The grinning face is one code point above U+FFFF, which UTF-16 stores as a surrogate pair of two units โ€” and .length counts units. Iterating with for...of or spreading into an array counts code points and gives 1.
Are รฉ and e + combining accent the same character?
Visually yes, technically no: U+00E9 is one code point, while U+0065 followed by U+0301 (COMBINING ACUTE ACCENT) is two. They are canonically equivalent, and the NFC and NFD normalization forms exist so that comparisons and storage can settle on one form.
Is ASCII still relevant in a Unicode world?
Constantly โ€” as Unicode's first 128 code points. UTF-8 encodes each of them as the same single byte ASCII always used, so every ASCII text is valid UTF-8, and the classic control characters from that range still drive terminals and protocols.
How do I identify a mystery character?
Paste it into a code point lookup: it reports the U+ number, decimal value, official name, block and plane, plus the UTF-8 and UTF-16 byte layouts. That turns an unrenderable box into a precise identity you can search for and replace.