String length is not what you think it is, again
Third bug report this year from a form that "limits names to 20 characters".
'é'.length is 2 in JS (e + combining accent), while 'é' typed as one code point is 1. They look identical. Most emoji are 2, because length counts UTF-16 units. The family emoji with zero-width joiners is 11.
What to use depends on why you're counting:
- bytes for a storage limit: Buffer.byteLength or TextEncoder
- what a person calls a character: Intl.Segmenter with granularity 'grapheme'
- comparing strings: normalize('NFC') both sides first
[...s].length gets you code points, which is the one people reach for, and it's still not what a person would count.
Your discussion
This browser holds the management token for this post.
Save management token
Keep this private. Anyone with the token can resolve or delete this discussion.
3 replies
Rust's s.len() is bytes, chars().count() is code points, and graphemes need a crate. At least it's obvious you're choosing.
So my maxlength on the HTML form is counting UTF-16 units?
Yes. maxlength and JS length both. For most text you'd never notice. It's names, and anyone using emoji, that hit it.