Here are two ways to write an accented letter: é and e followed by a combining acute accent. A reader may see the same letter. A program inspecting the underlying sequence can see different lengths. Neither observation requires a broken font or corrupt text. The program and the reader are using different rulers.
This is a small problem with large reach. It appears in a biography field that rejects a person's name, a cursor that stops inside an emoji, and a database budget expressed in bytes while the interface promises characters. Before choosing a clever string function, it helps to decide what the ruler is supposed to measure.
Put the rulers beside each other
For this article, a small local check used Node 24.2.0 and an Intl.Segmenter configured for grapheme segmentation. It counted UTF-8 bytes, Unicode code points, JavaScript UTF-16 code units, and segmented grapheme clusters. The results below describe these particular strings and that execution, rather than every possible text-processing environment.
| Text representation | UTF-8 bytes | Code points | UTF-16 code units | Grapheme clusters |
|---|---|---|---|---|
Precomposed é |
2 | 1 | 1 | 1 |
e plus combining acute accent |
3 | 2 | 2 | 1 |
👩🔬 |
11 | 3 | 5 | 1 |
The emoji sequence joins a woman and microscope with a zero-width joiner. The table is a useful reminder that the length of a JavaScript string is not a count of the visible symbols a reader necessarily recognizes. It also shows why a visible-character limit cannot, by itself, guarantee a small storage footprint.
Unicode's text-segmentation annex defines default boundaries for grapheme clusters, words, and sentences. Grapheme clusters approximate user-perceived characters and are useful for editing and counting. The specification also explains that user perception and appropriate behavior can depend on language and context. A sensible default is a foundation for an interface, not a claim that writing systems all behave alike.
Decide what the limit is doing
Suppose a fictional exhibition catalog allows a short contributor introduction. The visual design wants roughly comparable amounts of reading. Storage and request handling need bounded data. Those are two requirements, and they can be expressed separately: a user-facing text budget and an explicit byte or payload budget.
A byte-only counter would make some writing systems consume the displayed allowance faster than others. A grapheme-only counter would describe the reading experience better but would not necessarily bound storage tightly. Combining the two budgets can be reasonable when the interface explains the relevant limit instead of calling every rejection “too many characters.”
The exact numbers should come from the product's needs. The useful design exercise is to test names and introductions from the people who will actually use it, including combining marks and emoji. A test corpus should contain ordinary international text, rather than reserving every non-ASCII example for an adversarial test. Most of these strings are simply people writing normally.
Equality needs a purpose too
The two accented-letter representations also raise a matching question. If the catalog searches for a contributor's name, should either representation find the record? Unicode's normalization annex defines canonical and compatibility normalization forms. Canonical normalization can bring the two representations into a common form, while compatibility normalization intentionally folds additional distinctions.
The same local check illustrates the difference with ①. NFC leaves the circled digit as it is. NFKC maps it to 1. That transformation may help a particular search or identifier policy. In a transcription whose purpose is to preserve the printed form, discarding the circle might remove information the editor meant to retain.
It follows that “normalize all strings” is an incomplete instruction. Which normalization, at which boundary, for which comparison? The exhibition catalog might preserve the submitted display text while deriving a separate comparison key under a documented policy. That is a proposed design, not a claim that any particular database implements it automatically.
Search is not a reversible edit
W3C's character-model guidance on string matching distinguishes case folding for comparison from case mapping for display and discusses language-sensitive behavior. A transformation that makes searching convenient may discard information needed to reconstruct the original spelling. Keeping a comparison key should not require replacing the person's display name with that key.
This is another place where two operations look deceptively similar. Searching for a contributor, formatting a heading in capitals, and deciding whether an account identifier collides each ask a different question of text. Applying one transformation everywhere can make the code shorter while making the product's behavior harder to explain.
Visual similarity is separate again. Unicode's security mechanisms provide confusable-detection tools and discuss the limitations of such comparisons. Two strings that look alike need not be canonically equivalent. Detecting that resemblance does not automatically justify rewriting one person's name into another alphabet or declaring every mixed-script phrase illegitimate.
A small contract with the writer
For the imaginary catalog, I would specify the behavior in ordinary terms before writing the validation code. The introduction counter approximates visible characters. A separate maximum bounds the payload. Search can compare normalized keys, while the display preserves the accepted spelling. Identifier checks, if any, get their own stated rules. Each choice has a purpose a maintainer can name.
The implementation then has something meaningful to verify. Does the combining accent remain attached when text is shortened? Does a search find both canonically equivalent spellings? Does an error identify the limit the user actually crossed? These proposed checks are more useful than one assertion that the string has a particular raw length.
There is pleasure in this precision because it brings software closer to the material it handles. Text is an encoding and a human practice at the same time. The four rulers do not have to compete. We just need to stop handing a storage ruler to a writer while calling it the measure of a letter.
A thought worth keeping?



