Zenaique

What happens to emoji ZWJ sequences under cl100k_base vs. o200k_base pre-tokenization?

Short answer·Hard·4.0 · 0·~3 min·Asked atGnaniKore AiOpenAI
Attempt it

Explain the role of regex based pre-tokenization in cl100k_base (GPT-4) and o200k_base (GPT-4o). Focus specifically on how each handles Unicode ZWJ (Zero Width Joiner) emoji sequences, and why the o200k_base regex was updated.

Free · 2 AI evals / day
TL;DR

Neither regex has a ZWJ rule: cl100k_base keeps a ZWJ emoji in one chunk, and o200k_base may even split it at U+FE0F. o200k's lower count (6 vs 9 for 🏳️‍🌈) comes from its larger vocabulary.

Memory aid
Sign in to see the mnemonic that makes this stick.
Easy to grasp

Picture a sticker made of three smaller stickers taped together with invisible tape: a face, a tape strip, and a heart that together mean one thing. Both the older and the newer system keep the taped sticker in one bag. But the price is set by the price list, and the newer system has a longer price list with cheaper bundles for the pieces. The invisible tape is the zero-width joiner, an unprintable character that glues emoji parts into one symbol, and the price is how many tokens the text costs.

Concept explanation~2 min read

Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.

Emoji look like single characters. To a tokenizer, though, they are often short sequences: a base symbol, an invisible joiner, and one or more further symbols that a renderer fuses into one glyph. That gap between what you see and what the bytes contain is why the same rainbow flag can cost nine tokens on one OpenAI model and six on another.

Three layers that are usually discussed separately work together here: Unicode grapheme clusters, the pre-tokenization regex, and the BPE merge constraint. People who think emoji are single codepoints cannot explain the fragmentation. People who think BPE can stitch fragments back together miss the hard boundary rule. People who credit the emoji savings to a regex rule for emoji miss that the vocabulary is the real lever here.

What a ZWJ emoji sequence is in bytes

A surprising number of emoji are not single Unicode codepoints. They are grapheme clusters: several codepoints that a text renderer combines into one visible glyph. The glue is the zero-width joiner, codepoint U+200D, which prints nothing but tells the renderer to fuse its neighbours. A rainbow flag, for example, is a waving white flag, a variation selector that requests emoji presentation, the joiner at U+200D, and a rainbow. That is four codepoints for one glyph.

In UTF-8, each of those codepoints expands to multiple bytes. The joiner alone is three bytes, and the emoji codepoints are four bytes each. So a single rainbow flag is 14 raw bytes before any tokenization decision is made. Skin tone variants, family emoji, and many flags follow the same pattern: a base plus modifiers plus joiners.

The visible glyph is built from a sequence. How many tokens it costs depends on two things: where the regex cuts the sequence, and which byte merges the vocabulary has. Nothing about the picture you see determines that.

How cl100k_base handles the cluster
What o200k_base changed, and where the emoji savings come from
Why OpenAI made the change, and what it means for cost
The limit of the vocabulary: rare emoji still fragment
Sign in to unlock the full deep dive.

Situations where this technique stops working.

Sign in to see when this approach fails.

2–4 min · Everything important, quickly.

Sign in to see the quick scan of the deep dive.
python
import tiktoken

cl100k = tiktoken.get_encoding("cl100k_base")
o200k = tiktoken.get_encoding("o200k_base")

flag = "\U0001F3F3\uFE0F\u200D\U0001F308"  # rainbow flag (ZWJ sequence)

print(len(cl100k.encode(flag)))  # 9: one chunk, few emoji merges in the vocabulary
print(len(o200k.encode(flag)))   # 6: two chunks, but more byte merges in the vocabulary

# Always resolve the encoding from the model so the regex matches:
enc = tiktoken.encoding_for_model("gpt-4o")  # -> o200k_base
Aspectcl100k_base (GPT-4)o200k_base (GPT-4o)
ZWJ emoji sequenceOne chunk (symbol branch; no ZWJ rule)Usually one chunk; split after U+FE0F, which counts as a mark
Tokens for the rainbow flag 🏳️‍🌈9 (few emoji merges)6 (more byte merges)
Emoji modifiers (skin tone, flags)One chunk, many byte-level tokensOne chunk, fewer tokens
Multilingual character runsBreaks at combining marks (Devanagari vowel signs)Keeps combining marks with their letters
Design motivationASCII-tunedMultilingual and multimodal

Real products, models, and research that use this idea.

  • OpenAI's o200k_base, used by GPT-4o and GPT-5, encodes common emoji in fewer tokens than cl100k_base (6 versus 9 for the rainbow flag), mainly because its vocabulary has more byte merges.
  • Messaging and social products with heavy emoji usage see lower per-message token bills when they move to o200k-based models for the same text.
Sign in to see more production examples.

What an interviewer would ask next. Try answering before peeking at the approach.

QHow would you estimate the token-cost savings of moving an emoji-heavy chat product from a cl100k model to a GPT-4o model?
A

Sample real messages, encode under both encodings with tiktoken, weight the per-message token delta by traffic volume.

2 more follow-ups an interviewer would ask next. Sign in to reveal them.

Red flags & common mistakes

The phrases that signal junior thinking. Click to expand.

Most common mistake

Assuming o200k_base added a regex rule that keeps ZWJ emoji whole; neither regex mentions U+200D, and o200k's savings on emoji come from its larger vocabulary.

Sign in to see all red flags and common mistakes.

60 second bullets to scan on the way to the call.

  • What a ZWJ emoji sequence is at the codepoint level

  • Why pre-tokenization cuts are walls BPE cannot cross

Sign in to unlock the revision sheet.

Primary sources. Browse if you want the original framing.

Similar questions

Same topic, related formats. Practice these next.

4 curated
Next question
Why use subword tokens, and what is wrong with word level or character level?
Flashcard·Easy