October 19, 2026 · 6 min read
Unicode and text encoding explained without the jargon overload
What UTF-8, code points, and mojibake actually are, explained through the garbled email subject line that started it all.
Years ago I got an email with the subject line "Meeting notes for FridayÂ" — those odd  characters sprinkled between every word weren't a typo from the sender, they were the visible scar tissue of a text encoding mismatch, and once I understood what had actually happened I couldn't unsee the same pattern showing up in database exports, web forms, and old text files for years afterward. This is the explanation I wish someone had given me before I spent an evening guessing at the problem.
What a character encoding actually does
Computers only store numbers, so every system needs an agreed-upon table mapping numbers to the letters, symbols, and punctuation marks a human wants to see. A character encoding is that table. The letter "A" being stored as the number 65 is not a law of physics, it's a convention — a very old and stable one, part of the ASCII standard from 1963, but a convention nonetheless. The moment you need characters ASCII never accounted for — accented letters, currency symbols, non-Latin scripts, emoji — you need a bigger table, and that's where the real complexity starts.
Unicode is the table; UTF-8 is how you write it down
This is the distinction that trips up almost everyone at first: Unicode itself is just a giant, continually growing list assigning a unique number (called a code point) to every character anyone has asked to have represented — Latin letters, Cyrillic, Han characters, mathematical symbols, emoji, all of it. UTF-8 is one particular scheme for turning those numbers into actual bytes on disk or over a network. There are other schemes too (UTF-16, UTF-32, the older Latin-1), but UTF-8 has become the default nearly everywhere on the web because it's backward-compatible with plain ASCII for the first 128 characters and uses variable-length byte sequences that keep common text compact.
Why mojibake happens at all
Mojibake — garbled text like the  characters in that email, or worse-looking sequences like "café" rendering as "café" — happens when bytes written in one encoding get read back using a different encoding's rulebook. A letter like é, which UTF-8 stores as two specific bytes, gets misread by a program assuming Latin-1 encoding as two separate single-byte characters instead of one combined character, and the result is exactly the kind of double-character garbage that shows up in badly configured emails, web pages missing a charset declaration, or CSV files opened with the wrong assumed encoding.
Code points, glyphs, and why 'one character' is a slippery idea
It gets more layered once you look closely: a single visible character on screen (a glyph) isn't always a single Unicode code point. Some accented letters can be represented either as one combined code point or as a base letter followed by a separate combining accent mark — two different byte sequences that render identically to the human eye but compare as unequal in code that does naive string matching. This is a real, recurring bug source in search boxes and deduplication logic, and it's why some programming languages and libraries offer explicit "normalization" functions that convert text into one consistent representation before comparing it.
Where this shows up in ordinary, non-technical work
You don't need to write parsing code to run into this. A Word document with curly quotes pasted into a plain-text field, a spreadsheet exported from an older accounting system, a URL containing non-English characters, or a webpage missing its charset meta tag can all produce visible corruption. When it happens, checking a document's actual byte-level content — for example, running suspicious text through a base64 encoder or viewing raw bytes — can confirm whether the underlying data is intact and only the display is wrong, versus actual data loss where the original characters are genuinely gone.
Percent-encoding and URLs: a related but separate problem
URLs add another layer because certain characters (spaces, ampersands, non-ASCII letters) aren't safe to put directly into a URL, so they get percent-encoded instead — a space becomes %20, for instance. This is not the same mechanism as UTF-8 versus Latin-1 confusion, but the two problems often get tangled together in the same bug report, because a non-English character in a form field first needs correct text encoding and then correct URL encoding on top of it. A URL encoder / decoder tool is the fastest way to check whether a broken-looking link is a percent-encoding problem or a deeper character-encoding one, by decoding it and seeing whether readable text comes back out.
Practical habits that avoid most of this pain
Default every new file, database column, and API response to UTF-8 explicitly rather than relying on a system default that varies by operating system and region. Always declare the encoding in HTML documents' head section and in HTTP response headers rather than leaving it to guesswork. When a text file misbehaves, check its actual byte content before assuming the data itself is wrong — often it's only the interpretation that's broken, and re-reading the same bytes with the correct encoding restores everything perfectly. And when comparing or deduplicating text values programmatically, normalize the strings first so visually identical characters are guaranteed to be treated as equal.
Straight answers to the questions people actually ask
Why do emoji sometimes show up as boxes or question marks? That's usually an outdated font or an encoding that doesn't support the character's code point at all — the underlying data is often fine, but the specific rendering environment doesn't have a glyph to display for it.
Is UTF-8 always the safest choice for a new project? For nearly all modern web and application work, yes — it's the de facto universal standard, handles every language, and stays compact for English-heavy text.
Can mojibake damage data permanently? Sometimes — if a program actively re-saves misread text using the wrong encoding, the original bytes can genuinely be lost rather than just misdisplayed, which is why it's worth diagnosing an encoding problem before doing any bulk re-save operations on the affected file.
What's the quickest way to check what encoding a file actually is? A hex or plain-text editor showing raw bytes near the top of the file often reveals a byte-order mark or an obviously wrong sequence; dedicated encoding-detection tools are more reliable for ambiguous cases where visual inspection isn't conclusive.