The useful part, up front

What you’ll take away

  • A token stage can preserve all bytes it receives while an earlier normalizer changes the raw source representation.
  • NFC joins the two declared accented-e forms; NFKC also folds the fi ligature into ordinary letters.
  • Our complete byte-token vocabulary needs no unknown token, but that does not undo earlier normalization.
  • Offsets identify spans in a named source and unit; they do not generally contain the discarded source text.
  • Normalizing pieces before joining them and encoding pieces before joining them create different boundary questions.
  • Name the equality test and retain the original when exact source representation matters.
01

A readable decoded string may answer the wrong question

You save a passage, turn it into tokens, then decode those tokens back into text. The result reads correctly. Has the process preserved the exact passage? That depends on which version of the text reached the token encoder and what the decoder promises to return.

A tokenizer can be a pipeline rather than one indivisible step. Hugging Face’s Tokenizers guide separates normalization, preliminary splitting, the vocabulary model and later processing; decoding has its own behavior too [1]. Some steps can change the input string before the vocabulary model chooses tokens. Reversing the last step cannot automatically reverse every earlier change.

We will build a deliberately small byte-token system whose entire rule is visible, then place Unicode normalization in front of it. Four short strings reveal what survives and what becomes indistinguishable. The byte and normalization examples were checked with an original Python script. They are teaching examples, not token counts from a commercial model. The practical question is whether an application needs readable normalized text, equivalent text or the exact original representation.

Four inputs have four precise source representations. Original inventory. UTF-8 bytes below are hexadecimal; code points identify characters independently of their appearance in a particular font.
Original inventory. UTF-8 bytes below are hexadecimal; code points identify characters independently of their appearance in a particular font. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
02

Name the characters before counting their bytes

Start with an accented e. One string contains the single code point U+00E9, written é. Another contains U+0065, the ordinary letter e, followed by U+0301, a combining acute accent. These can represent the same accented letter while using different code-point sequences. Naming the code points avoids relying on how a particular font displays them [3].

UTF-8 gives those strings different byte sequences. The single-code-point version uses decimal bytes (195, 169), while the two-code-point version uses (101, 204, 129). UTF-8 represents different code points with different numbers of bytes, so a byte count and a code-point count need not match [4].

Our second pair is the fi ligature, U+FB01, written fi, and the two ordinary letters fi, U+0066 followed by U+0069. The ligature uses bytes (239, 172, 129); the two letters use (102, 105). We now have four precisely identified inputs. Their visual similarity is useful context, but the code-point and byte lists tell us exactly what any later operation receives.

03

Use a token vocabulary small enough to specify completely

Our invented vocabulary gives every possible byte its own token. Identifiers 0 through 255 stand for the byte with that same numeric value. Add one extra token: identifier 256 stands for the two-byte sequence (102, 105), which spells fi. That makes 257 vocabulary entries.

To encode a string, first obtain its UTF-8 bytes. Read from left to right. Whenever the next two bytes are (102, 105), emit token 256 and move forward by two bytes. Otherwise, emit the current byte’s identifier and move forward by one. There are no other merges, omitted spaces, added prefixes or special markers in this example.

The two ordinary letters fi therefore become (256). The ligature fi becomes (239, 172, 129), since its bytes do not match our merge. The two accented-e forms become (195, 169) and (101, 204, 129). These counts belong to our stated rule. The useful feature is that every output token has a known byte payload, so we can examine preservation without guessing how a real vocabulary was trained.

04

Merging two bytes need not lose either byte

Our decoder looks up each token’s byte payload, joins the payloads in order and interprets the complete result as UTF-8. Token 256 expands to (102, 105), so decoding (256) returns fi. Decoding (239, 172, 129) returns the original ligature fi. The distinction between the two source strings survives this encoder and decoder.

The reason is visible at every step. A one-byte token stores exactly the byte the encoder consumed. The extra token stores exactly the two bytes it consumed. Nothing is deleted, reordered or replaced by a guess. Joining those payloads recovers the input byte sequence, whether or not a merge occurred.

A token containing only part of a multi-byte character need not be readable by itself. Our decoder joins all payloads before decoding the complete UTF-8 string. Readability of each separate token is therefore not the preservation test. The right check for this stage is whether the complete decoded bytes equal the complete bytes supplied to it. For our four examples, they do.

Normalization changes the string that our encoder receives. Original 257-entry vocabulary; decimal IDs 0–255 mean their byte values and ID 256 means bytes 102,105. These are not outputs from a commercial tokenizer.
Original 257-entry vocabulary; decimal IDs 0–255 mean their byte values and ID 256 means bytes 102,105. These are not outputs from a commercial tokenizer. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
05

NFC can preserve the accented letter while changing its representation

Now insert an NFC normalization step before our byte encoder. Unicode defines this form using canonical decomposition and composition [3]. In our accented-e pair, both the single U+00E9 and the sequence e plus combining acute become the same normalized string, U+00E9.

Both inputs now reach the encoder as bytes (195, 169) and produce tokens (195, 169). Decoding returns é in each case. The accent has not been removed. What disappeared was the distinction between writing the accented letter as one code point and writing it as two. Plain unaccented e remains a different string in this example.

The byte encoder is still doing its lossless job on the bytes it receives. It never sees the earlier two-code-point representation after NFC has replaced it. If the application’s goal is comparison under canonical equivalence, this shared form may be useful. If the goal is to reproduce the exact earlier bytes, the normalized tokens alone no longer supply enough information. The preservation question has moved to an earlier stage.

06

NFKC makes a broader choice about which distinctions to fold

NFC leaves our fi ligature distinct from the ordinary letters fi. NFKC makes a different choice: the ligature becomes the two letters. Unicode documents this compatibility decomposition and distinguishes it from the canonical normalization used in the previous example [3].

After NFKC, both forms reach our encoder as (102, 105), which becomes the single token (256). Decoding returns fi. That result faithfully represents the normalized input, yet it cannot tell us whether the source used the ligature. Both accented-e inputs also become the same accented-e form under NFKC in our example.

The broader change is not automatically appropriate for every document. A search application may deliberately want certain alternative forms to match. A quotation archive may also need to retain the exact source representation. Unicode cautions that compatibility normalization can erase distinctions that matter in some contexts [3]. Preserve the original separately when those distinctions are part of the record, and describe the normalized copy by the operation that produced it.

07

Follow the difference through one complete word

Extend the ligature example into the word fish, with a ligature followed by s and h. Our raw encoder produces (239, 172, 129, 115, 104). The ordinary-letter version fish produces (256, 115, 104). The sequences differ because the first encoder receives the ligature’s three bytes, while the second can use our fi merge.

Apply NFKC first and both words become ordinary fish. Both now produce (256, 115, 104), and both decode to fish. The system can represent every byte it receives, and it has no unknown-token problem. It still cannot recover the earlier distinction from those token identifiers alone.

This separates two useful questions. Coverage asks whether the encoder can represent its input. Preservation asks whether the complete process retains the distinctions that matter about an earlier source. Our vocabulary has complete byte coverage by construction. The loss of the ligature distinction happened before byte encoding, so adding more byte coverage would not repair it. Keeping the original source would.

A normalized token can point to different original spans. Original hand-declared alignment after NFKC. Spans use half-open original code-point offsets, not byte offsets or measured library output. Both normalized words have IDs (256,115,104).
Original hand-declared alignment after NFKC. Spans use half-open original code-point offsets, not byte offsets or measured library output. Both normalized words have IDs (256,115,104). · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
08

Offsets help locate original text when the original is retained

Hugging Face’s components guide describes tracking alignment during normalization so generated tokens can be related back to the input [2]. That is useful for highlighting a source passage, but a location and the text stored at that location are different pieces of information.

In our fish example, the normalized fi token corresponds to original code-point positions from 0 up to, but not including, 1. In ordinary fish, it corresponds to positions from 0 up to 2. We have declared those alignments for this example; they are not outputs measured from the library. If the original string is retained, the span identifies the corresponding source substring.

Offsets alone are not a universal substitute for that source. Consider a separate rule that changes ASCII A into a. Original A and original a both become a, both produce token (97), and both occupy the original span [0, 1). Their byte spans are the same too. Neither the normalized token nor those offsets says which letter appeared originally. Alignment metadata needs a clearly identified source and a stated unit.

09

Joining normalized pieces can create a new normalization boundary

Suppose an application receives e in one piece and the combining acute accent in the next. Each piece is already unchanged by NFC when considered alone. Normalizing them separately and joining the results gives the two-code-point sequence e plus acute.

Normalize the complete joined string instead and NFC produces the single code point é. Unicode explicitly explains that concatenating normalized strings does not always leave the result normalized [3]. The boundary between pieces can create a combination that was not present inside either piece on its own.

Our byte encoder makes the difference concrete. The separately normalized and then joined form yields (101, 204, 129). The form normalized after joining yields (195, 169). Applying NFC once more to the joined two-code-point string brings it to the latter form. The lesson is to record where normalization happens in a pipeline that assembles pieces. The word normalized is incomplete unless it identifies the form and the text boundary to which that operation was applied.

The join matters at two different stages. Two original boundary examples. The accented-e cases compare NFC placement; the f/i cases use no normalization and compare where our fi merge can occur.
Two original boundary examples. The accented-e cases compare NFC placement; the f/i cases use no normalization and compare where our fi merge can occur. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
10

Equal decoded text can still have different token sequences

There is another boundary effect even when no normalization occurs. Encode f alone with our rule and the result is (102). Encode i alone and the result is (105). Joining those two token lists produces (102, 105). If we instead join the text first and encode fi, our merge produces (256).

Both token lists decode to the same two bytes and the same text, fi. One list contains two tokens and the other contains one. The difference comes from whether the encoder was allowed to see the byte pair together. It does not indicate that either list lost the text it represents.

This is a separate result from the earlier normalization example. There, different original strings became the same normalized tokens. Here, the same decoded text has two possible token sequences under different assembly procedures. For a system that stores tokens, records where the text was divided can therefore matter. Exact decoded-text equality does not, by itself, establish that an independently assembled token sequence matches the encoder’s output for the complete text.

11

State what the decoder should preserve

Our decoder is intentionally strict: it expands the known payloads in order and joins bytes before interpreting the string. Real tokenizer pipelines can have additional decoding choices. The Hugging Face guide discusses converting identifiers back to vocabulary pieces, handling special tokens and choosing a decoder that understands the tokenizer’s piece markers [1][2]. Those details belong in a round-trip check.

Choose the comparison that matches the task. For a raw-text archive, compare the reconstructed source representation with the saved original. For canonical matching, compare the chosen normalized forms. For our token-assembly example, compare the token identifiers as well if identical sequences are required. A readable preview alone does not perform all these checks.

The criterion should also name the boundary. Comparing decoded output with the string after normalization can correctly pass while comparison with the earlier raw string fails. Both results can be accurate. Reporting which inputs were compared makes the result useful and prevents a successful check of one stage from being presented as preservation by the entire pipeline.

12

Retain the source and the transformations that connect it to tokens

A useful record keeps the original string, its encoding, the normalization choice, the string actually submitted for tokenization, the tokenizer’s identity and the decoding settings. If text was processed in pieces, record those boundaries too. These are the details needed to explain why a decoded passage does or does not reproduce its source.

For our four inputs, the results are precise. Raw encoding preserves all four strings. NFC makes the two accented-e representations identical while keeping the ligature distinct from fi. NFKC also makes the ligature and ordinary letters identical. Each token count follows from the complete 257-entry rule we declared, rather than from an estimate based on appearance or word length.

An application can retain a normalized working copy and the original source for different purposes. That gives readers and future processing steps a way to inspect the actual quotation when exact representation matters. The decision is about which distinctions the task needs. A readable decoding is useful evidence, but its meaning comes from the source, transformations and equality test that accompany it.

Choose the equality test that matches the task. Original comparison guide. An application can require more than one test; a readable preview does not perform every comparison automatically.
Original comparison guide. An application can require more than one test; a readable preview does not perform every comparison automatically. · Ameer Journal — original explanatory diagramOriginal editorial illustration; no third-party artwork reused.
Follow the evidence

Sources & further reading

Explore the references behind this guide. External pages may change after our review.

  1. The tokenization pipeline · Hugging Face
    Hugging Face · Accessed 7 Nov 2026
  2. Components · Hugging Face
    Hugging Face · Accessed 7 Nov 2026
  3. UAX #15: Unicode Normalization Forms
    Unicode Consortium · Accessed 7 Nov 2026
  4. RFC3629: UTF-8, a transformation format of ISO10646
    IETF / RFC Editor · Accessed 7 Nov 2026

Article updated 7 Nov 2026.

Found something we should revisit?

Good explanations get better with thoughtful feedback.

Suggest a correction