Reference library

Unicode and encodings: UTF-8, UTF-16, and code points

Code points, UTF-8 bytes, UTF-16 code units, normalization, BOM, and encoding error diagnostics.

From text to bytes

Four different levels

  1. GraphemeWhat the reader perceives: A, é, or 👩‍💻.
  2. Code pointAn abstract Unicode number such as U+1F600.
  3. Code unitA storage unit: 8 bits in UTF-8, 16 bits in UTF-16.
  4. ByteThe actual values written to a file or sent over a network.
Encoding table

The same text at every level

Copy a character, its code points, UTF-8 bytes, or UTF-16 code units. Spaces separate individual values.

Unicode examples with UTF-8 bytes and UTF-16 code units
Character Code point UTF‑8 UTF‑16 What it shows
Single code pointsA single Unicode character can occupy one to four bytes in UTF-8. 6
Latin AASCII is preserved by UTF-8 and occupies one byte.
Cyrillic YaMost Cyrillic letters are encoded with two UTF-8 bytes.
Precomposed éThe precomposed accented letter is represented by one code point.
Euro signThis Basic Multilingual Plane character occupies three UTF-8 bytes.
Han character 中A typical CJK ideograph also occupies three UTF-8 bytes.
EmojiA code point outside the BMP: four UTF-8 bytes and a UTF-16 surrogate pair.
SequencesOne visible grapheme can consist of several code points. 4
Decomposed éThe letter e plus a combining acute looks like é but remains two code points.
Woman technologistTwo emoji are joined with ZERO WIDTH JOINER U+200D.
Flag of RussiaThe flag is built from two regional indicators rather than one character.
Emoji with modifierA base emoji and a skin-tone modifier form one visible grapheme.
Practical recipes

Declarations, conversion, and normalization

Copy complete declarations and API calls. Each group solves a different layer of the encoding task.

Unicode and encoding recipes
TaskCode or bytesWhen to use
Web and HTMLHow to declare UTF-8 and reference a character without typing it directly.3
HTML encoding declaration Place it near the start of head so the browser decodes the document as UTF-8 immediately.
HTTP header The server-side response declaration; it must match the actual bytes.
Numeric HTML reference References a code point in HTML. This is markup syntax, not a separate encoding.
JavaScriptConvert strings to bytes and create characters from code points.3
String → UTF-8 Returns a Uint8Array containing UTF-8 bytes.
UTF-8 → string Decodes bytes; fatal: true turns an invalid sequence into an error.
Code point → character Creates 😀 without manually writing a UTF-16 surrogate pair.
NormalizationTurn equivalent sequences into a predictable form.3
NFC: composed form A common choice for storage, comparison, and interchange without folding compatibility distinctions.
NFD: decomposed form Decomposes precomposed characters into a base and combining marks.
NFKC: compatibility Folds compatibility variants such as fullwidth forms; use only when losing those distinctions is acceptable.
BOM and byte orderSignatures at the start of a stream; UTF-8 usually does not need a BOM.3
UTF-8 BOM A UTF-8 signature. UTF-8 has no byte order, so add it only when a format or application requires it.
UTF-16LE BOM Indicates little-endian byte order for UTF-16.
UTF-16BE BOM Indicates big-endian byte order for UTF-16.
Mojibake decoder

What the broken text is telling you

The visible pattern often points to the failed boundary, but recovery depends on preserving the original bytes.

Привет UTF-8 bytes were decoded as Windows-1251.

Return to the original bytes and decode them as UTF-8; do not blindly re-encode the already damaged string.

Привет UTF-8 bytes were decoded as Windows-1252 or a similar single-byte encoding.

Check charset in HTTP, HTML, and the file import settings.

������ The decoder encountered invalid bytes and inserted U+FFFD REPLACEMENT CHARACTER.

Find the original file or stream: once bytes become �, the lost values usually cannot be recovered from the string.

?????? The text was saved through an encoding that cannot represent the required characters.

Switch to UTF-8 before writing. If characters are already question marks, recover them from the source or a backup.

Quick notes

Keep text intact across boundaries

Use UTF-8 by default
Choose UTF-8 for new files, APIs, databases, and web pages, and declare it consistently at every boundary.
Keep the original bytes
When text is corrupted, diagnose the byte sequence before saving or re-encoding the visible mojibake.
Normalize deliberately
NFC is a practical default for comparison; NFKC changes compatibility distinctions and is not a universal cleanup pass.
Count user-perceived characters
String length, code-point count, and grapheme count can differ for emoji and combining sequences.

Encoding guidance checked against the WHATWG Encoding Standard; normalization and BOM behavior follow Unicode Normalization Forms and the Unicode UTF & BOM FAQ.

Related tools

Continue working with text

Copy a symbol, convert markup, clean a fragment, or keep the result in the notebook.

FAQ

Questions about Unicode and encodings

What is the difference between Unicode and UTF-8?

Unicode assigns characters abstract code points. UTF-8 is one way to encode those code points as bytes. UTF-16 and UTF-32 are other encoding forms.

Why is JavaScript "😀".length equal to 2?

JavaScript strings expose UTF-16 code units. U+1F600 is outside the Basic Multilingual Plane and therefore uses a surrogate pair: two code units.

Does a UTF-8 file need a BOM?

Usually no: UTF-8 has no byte-order ambiguity. A BOM can act as a signature, but add it only when a consuming format or application requires it.

Can mojibake always be repaired?

Only when the original bytes or a reversible sequence of wrong conversions is available. Replacement characters or question marks often mean information has already been discarded.

When should text be normalized?

Normalize at a deliberate system boundary, commonly to NFC before storage or comparison. Do not repeatedly apply compatibility normalization to arbitrary content.