Whitespace and the characters you cannot see
A large share of text problems come from characters that render as nothing or as an ordinary space. A non-breaking space looks identical to a normal space and prevents line breaking, which is why a stubborn line break refusal often traces to text pasted from a word processor. Zero-width spaces and joiners are invisible entirely and break search, comparison and validation silently.
Trailing whitespace at line ends is invisible and shows up as spurious differences in every diff. A byte-order mark at the start of a file is invisible in most editors and causes parse failures in JSON, CSV and shell scripts, where it appears as stray characters before the first real content.
Line endings are the other recurring case: Windows CRLF against Unix LF, where the carriage return is invisible. Two files that look identical can differ on every line for this reason. Normalising whitespace, line endings and invisible characters is usually the right first step when text is behaving inexplicably.
Unicode normalisation and lookalikes
Unicode allows the same visible character to be encoded in more than one way. The letter é can be a single precomposed code point, or an e followed by a combining acute accent. Both render identically and neither is wrong, but they are different byte sequences — so string comparison fails, search misses, and a username can appear duplicated.
Normalisation forms resolve this: NFC composes characters into their precomposed form and is the right default for storage and comparison, while NFD decomposes them. macOS has historically used decomposed form in filenames, which is why filenames with accents copied between systems sometimes fail to match.
Homoglyphs are the security-relevant case. Cyrillic а, Greek ο and Latin a and o are visually indistinguishable in most typefaces, and they are used to register deceptive domain names and impersonate usernames. Text that looks correct but fails a comparison is worth checking for mixed scripts.
Counting text is ambiguous
There is no single correct character count. JavaScript's length counts UTF-16 code units, so characters outside the basic multilingual plane — including most emoji — count as two. An emoji with a skin-tone modifier counts as four, and a family emoji built from several joined characters can count as eleven while being one visible glyph.
What users perceive as a character is a grapheme cluster, which is what a segmentation-aware counter measures. Byte length is different again and depends on encoding: UTF-8 uses one byte for ASCII, two for most Latin-script accented characters, three for most CJK, and four for emoji.
This matters wherever limits are enforced. A database column limited by bytes accepts fewer characters of Japanese than of English, and a form limited by JavaScript's length lets a user enter half as many emoji as they expect. Word counting has its own ambiguities across languages that do not delimit words with spaces — Chinese, Japanese and Thai — where character counts are the meaningful measure instead.