Three layers of a text value
A person sees a sequence of visible text, sometimes including a mark that combines with the preceding letter. Unicode assigns code points to abstract characters, while an encoding such as UTF-8 turns those code points into bytes for storage or transmission. One visible character can involve more than one code point, and one code point can take more than one UTF-8 byte. Counting bytes therefore does not necessarily count letters or user-perceived characters. The text-to-code-points tool shows the Unicode values in a string; text-to-UTF-8-bytes shows a different layer. Use these views to diagnose a mismatch, not as alternative spellings that can be substituted without considering the receiver's encoding.
The two spellings of café
The visible word café can end with the single code point U+00E9, LATIN SMALL LETTER E WITH ACUTE. This is a composed form. It can also end with U+0065, LATIN SMALL LETTER E, followed by U+0301, COMBINING ACUTE ACCENT. The latter has one extra code point even though the rendered word often looks the same. In UTF-8 the composed word has hexadecimal bytes 63 61 66 C3 A9; the decomposed word has 63 61 66 65 CC 81. Those are not the same byte sequences, so a byte-by-byte comparison or hash can differ. NFC maps this example to the composed sequence, while NFD maps it to the decomposed one. The embedded converter displays these bytes in decimal: 99 97 102 195 169 for the composed spelling and 99 97 102 101 204 129 for the decomposed spelling. Compare these values with the hexadecimal notation above.
- café: U+00E9 → C3 A9 at the end
- café: U+0065 U+0301 → 65 CC 81 at the end
- NFC ⇢ composed · NFD ⇢ decomposed
What normalization does and does not do
Unicode normalization provides defined ways to choose a representation for canonically equivalent sequences. NFC uses canonical composition after decomposition, whereas NFD leaves a canonical decomposed sequence. This is useful before comparing text that came from different keyboards, files or systems. It does not translate words, remove accents or guarantee that all visually similar strings are equal. Some lookalike characters belong to different scripts or have distinct meanings. The compatibility forms NFKC and NFKD make broader changes and may erase formatting distinctions, so choose them only for a purpose that permits those changes. Keep the same normalization policy at every point where values are compared, indexed or hashed; otherwise visually matching inputs can still take different paths.
A reliable debugging sequence
When a name fails to match, preserve the original input first. Inspect its code points to see whether an accent is one precomposed character or a base letter plus combining mark. Inspect UTF-8 bytes to check the encoding that will actually travel across an API or be written to a file. Normalize copies to NFC or NFD and compare the resulting code points, then try the reverse UTF-8-byte converter to verify the exact bytes are valid and decode as expected. For file exchange, record the chosen encoding explicitly instead of assuming every application uses the same default. A damaged or replacement character usually points to a decoding problem; normalizing an already misdecoded string will not restore the lost original bytes.
Use the correct equality test
For exact file integrity, hashes and signatures, bytes are decisive: changing normalization changes the bytes and therefore the digest. For user-facing search or duplicate detection, a product may deliberately normalize first, but it should explain and test that rule. Case differences, punctuation, whitespace and language-specific collation are separate questions; NFC alone does not settle them. Do not silently alter a user’s spelling while displaying or exporting it unless the workflow calls for that. In the tools below, start with café, inspect the UTF-8 bytes, then paste a version typed with e plus a combining accent into the code-point and normalization tools. The comparison shows exactly where a visually small difference enters the data pipeline.