Text Encoding and Unicode
Text encoding is the mapping between characters and the bytes computers store. Unicode is the universal character set that covers modern and historical scripts, and UTF-8 is its dominant byte serialization. This topic covers how text moves from abstract characters to bytes and back, why encodings break, and how to handle text correctly across systems.
itComputer fundamentals | OpenSkills.info
Course pathWalk it in order
Look it upDip in anytime
Go furtherLeaves this page
Don't Panic
Don't Panic — Text Encoding and Unicode
Character encoding is the agreement that turns text into bytes and back again. Computers are devoted to bytes, which are excellent at being bytes and notably poor at explaining which alphabet they were meant to become. Before Unicode, different systems gave the same byte patterns different jobs. The result was mojibake: a document that had taken a brief, unwanted vacation through the wrong decoder.
Unicode supplies the shared map. It gives each character, an abstract unit of written language, a number called a code point. The code point is not the picture on screen; that picture is a glyph chosen by a font. Nor is it necessarily a byte. An encoding form such as UTF-8 turns the code point into bytes, and UTF-8 is now the usual choice because ASCII remains itself and other characters fit into one to four bytes.
Keep the layers separate: character, code point, code units, bytes. This prevents the most common category error in text work, namely declaring that the fifth byte is the fifth character. It may be sitting inside a UTF-8 sequence, looking innocent in hexadecimal and becoming much less innocent when cut in two. Decode before you index text, and cut byte streams only at character boundaries.
The second surprise is that one visible symbol can be several code points. An é can arrive as one precomposed code point or as an e with a combining acute mark. Both can look the same while their bytes disagree. Normalization chooses a standard representation for a use case; NFC handles canonical equivalents, while NFKC also folds compatibility forms and therefore loses distinctions. A byte comparison, a text equality comparison, and locale-aware sorting are three different questions wearing similar hats.
There are more edges because text is sociable. UTF-16 uses surrogate pairs for supplementary characters. A grapheme cluster is the user-perceived editing unit, not always one code point. A malformed byte sequence needs strict handling. Look-alike characters can spoof an identifier. None of this makes Unicode unmanageable; it means text needs a declared boundary and an explicit policy instead of a hopeful shrug.
Read the intro when the layer model or UTF forms need a full explanation. Use the slides for the relationships at a glance, then keep the cheatsheet nearby for byte patterns, normalization, and diagnosis. The practice reference and exercise turn the theory into byte output and a strict-decoding check. Field Notes covers the operational traps that appear after the strings leave the whiteboard and enter real systems.
Where this skill leads
Relevant careers
See how this topic contributes to broader role-level skill maps.
Sources
- https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-2/
Supports
- Unicode separates characters, code points, encoding forms, and encoding schemes
- A character is the smallest unit of written language with semantic value; glyphs are visual shapes chosen by a font
- Code points range from U+0000 to U+10FFFF and group into 17 planes of 65,536 each
- The Basic Multilingual Plane holds most modern scripts; supplementary characters sit above U+FFFF
- UTF-8 encodes each scalar value as one to four bytes; UTF-16 uses 16-bit code units; UTF-32 uses one 32-bit unit per scalar value
- The surrogate range U+D800 to U+DFFF is used only by UTF-16 and never maps to a character
- Combining marks attach to a base character, so one user-perceived character can contain multiple code points
- Canonically equivalent sequences render the same but differ in bytes; normalization resolves them
- Characters, once assigned, cannot be reassigned; character names are stable
- https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-3/
Supports
- A conformant process must detect ill-formed byte sequences and must not interpret them as characters
- The Unicode Standard defines encoding forms, encoding schemes, and conformance requirements
- https://www.rfc-editor.org/info/rfc3629/
Supports
- UTF-8 encodes each Unicode scalar value as one to four bytes
- The bit patterns distinguish leading bytes from continuation bytes; continuation bytes start with 10
- UTF-8 is self-synchronizing: a parser can find the next character boundary from any byte
- The shortest encoding is required; overlong encodings are invalid
- Surrogate code points are not valid in UTF-8
- https://www.unicode.org/reports/tr15/
Supports
- NFC, NFD, NFKC, and NFKD are the four normalization forms
- NFC composes canonically equivalent sequences; NFD decomposes them
- NFKC and NFKD apply compatibility decomposition, which is lossy
- Compatibility decomposition folds superscripts, subscripts, and fullwidth forms into their base
- https://www.unicode.org/reports/tr29/
Supports
- A grapheme cluster is a base character plus its combining marks treated as a unit
- Grapheme cluster boundaries govern cursor movement, selection, and deletion
- Extended grapheme clusters are the recommended boundary model
- https://www.unicode.org/reports/tr10/
Supports
- The Unicode Collation Algorithm supplies a default multilingual string ordering
- Code-point order is not a culturally expected sort order
- The algorithm provides a tailoring mechanism for locale-specific ordering; CLDR supplies locale data
- https://www.unicode.org/reports/tr39/
Supports
- Confusable detection identifies visually similar characters with different code points
- Restriction profiles limit which characters are accepted in secure identifiers
- The General Security Profile is a default recommendation for identifier safety
- https://www.unicode.org/reports/tr31/
Supports
- UAX
- Identifier modification and restriction profiles work alongside UTS
- https://www.w3.org/International/articles/definitions-characters/
Supports
- A character set, a coded character set, and a character encoding are distinct concepts
- Unicode code points range from 0x0000 to 0x10FFFF
- UTF-8 uses one byte for ASCII, two for several alphabetic blocks, three for the rest of the BMP, four for supplementary characters
- UTF-16 uses two bytes for BMP characters and four for supplementary characters
- UTF-32 uses four bytes for all characters
- A user-perceived character can be a sequence of code points; grapheme clusters approximate that unit
- https://www.w3.org/International/questions/qa-choosing-encodings.en
Supports
- UTF-8 is the recommended encoding for web content
- The charset declaration must appear early in an HTML document
- HTTP Content-Type and HTML meta tags declare the encoding at the boundary
- https://www.unicode.org/glossary/
Supports
- The Consortium's definitions for code point, scalar value, grapheme cluster, canonical equivalence, and related terms
- https://www.unicode.org/versions/Unicode17.0.0/
Supports
- Unicode 17.0 assigns 159,801 characters across 172 scripts
- The standard consists of the core specification, code charts, Unicode Standard Annexes, and the Unicode Character Database
- https://www.unicode.org/history/publicationdates.html
Supports
- Unicode release dates from Version 1.0 in 1991 through Version 17.0 in 2025
- Unicode 2.0 was released in July 1996, Unicode 3.0 in September 1999, Unicode 6.0 in October 2010, Unicode 7.0 in June 2014, and Unicode 10.0 in June 2017
- https://www.unicode.org/versions/Unicode17.0.0/core-spec/appendix-c/
Supports
- Unicode and ISO began aligning their universal character-code work in 1991
- Unicode 1.1 aligned with ISO/IEC 10646-1:1993
- Unicode 3.1 synchronized with ISO/IEC 10646-2:2001, which added supplementary characters
- Unicode 4.0 synchronized with ISO/IEC 10646:2003 and Unicode 5.0 synchronized with later amendments
- https://www.unicode.org/versions/Unicode1.0.0/
Supports
- Unicode 1.0 was the first published version of the standard in October 1991
- https://www.unicode.org/versions/Unicode1.0.0/V2ch01.pdf
Supports
- Unicode and the ISO draft standard agreed in October 1991 on changes that merged their repertoires into one numerical character encoding
- https://www.unicode.org/versions/components-5.0.0.html
Supports
- Unicode 5.0.0 was released on July 14, 2006
- https://www.unicode.org/faq/utf_bom.html
Supports
- Unicode 2.0 changed the early 16-bit-only version to encode the range U+0000 through U+10FFFF
- https://docs.python.org/3.12/howto/unicode.html
Supports
- Python bytes.decode accepts an encoding and an error handler
- The strict error handler raises UnicodeDecodeError for invalid input and replace uses U+FFFD
- https://engineering.fb.com/2019/09/26/android/unicode-font-converter/
Supports
- Zawgyi and Unicode can use the same code-point range for Burmese, making classification necessary before conversion
- Mixed Zawgyi and Unicode content complicated compatibility, search, moderation, account security, and review workflows at Meta
- Detection accuracy is weaker for short messages and conversion must handle content and device encoding
- https://engineering.fb.com/2021/07/22/core-infra/mysql/
Supports
- MySQL 8.0 collation defaults caused mismatches with older implicit utf8mb4 collations during Meta's migration
- The mismatches caused problems with replication and schema-verification tools
