Look-alike pairs test values
Pairs of values that are identical on screen and different in storage. 12 values, each with what it breaks and what a correct application does instead.
Type them one at a time with AltShiftN
in the palette, or take them all into a script with nkb emit look-alike-pairs.
Name with a Latin a
look-alike-pairs/latin-small-apair 1 of 2 Latin a against Cyrillic a
- 5 graphemes
- 5 code points
- 5 bytes
- 5 UTF-16 units
- What it breaks
- The control half of a pair - only meaningful next to its counterpart.
- What a correct application does
- Stored as typed.
Name with a Cyrillic a
look-alike-pairs/cyrillic-small-apair 2 of 2 Latin a against Cyrillic a
- 5 graphemes
- 5 code points
- 6 bytes
- 5 UTF-16 units
- What it breaks
- A Cyrillic letter identical in shape to the Latin one; two accounts that look the same to every human.
- What a correct application does
- Either both accepted as distinct and shown as distinct, or the second rejected as a duplicate.
Word with a Latin o
look-alike-pairs/latin-small-opair 1 of 2 Latin o against Greek omicron
- 5 graphemes
- 5 code points
- 5 bytes
- 5 UTF-16 units
- What it breaks
- The control half of a pair - only meaningful next to the Greek omicron below it.
- What a correct application does
- Stored as typed.
Word with a Greek omicron
look-alike-pairs/greek-omicronpair 2 of 2 Latin o against Greek omicron
- 5 graphemes
- 5 code points
- 6 bytes
- 5 UTF-16 units
- What it breaks
- The same shape from a third script; catches uniqueness checks that only handle Cyrillic.
- What a correct application does
- Same as above.
Accented word, composed
look-alike-pairs/nfc-lodzpair 1 of 2 Composed against decomposed accents
- 4 graphemes
- 4 code points
- 7 bytes
- 4 UTF-16 units
- What it breaks
- Control half: the accented letters written as single characters.
- What a correct application does
- Stored as typed.
Accented word, decomposed
look-alike-pairs/nfd-lodzpair 2 of 2 Composed against decomposed accents
- 4 graphemes
- 6 code points
- 9 bytes
- 6 UTF-16 units
- What it breaks
- The same word with combining marks; identical on screen, different in storage and in every comparison.
- What a correct application does
- Normalised on save, or compared in a normalisation-aware way.
Name with an ordinary space
look-alike-pairs/plain-space-namepair 1 of 2 Ordinary space against non-breaking space
- 12 graphemes
- 12 code points
- 12 bytes
- 12 UTF-16 units
- What it breaks
- The control half of a pair - an ordinary space, so that the non-breaking one has something to fail against.
- What a correct application does
- Stored as typed.
Name with a non-breaking space
look-alike-pairs/nbsp-namepair 2 of 2 Ordinary space against non-breaking space
- 1 space that is not an ordinary space
- 12 graphemes
- 12 code points
- 13 bytes
- 12 UTF-16 units
- What it breaks
- A non-breaking space where an ordinary one is expected; search never matches.
- What a correct application does
- Normalised, or treated as distinct consistently.
Range with a hyphen
look-alike-pairs/hyphen-minuspair 1 of 2 Hyphen against en dash
- 9 graphemes
- 9 code points
- 9 bytes
- 9 UTF-16 units
- What it breaks
- The control half of a pair, with the ASCII hyphen - it parses everywhere the dash below it does not.
- What a correct application does
- Stored as typed.
Range with an en dash
look-alike-pairs/en-dashpair 2 of 2 Hyphen against en dash
- 9 graphemes
- 9 code points
- 11 bytes
- 9 UTF-16 units
- What it breaks
- The typographic dash that arrives with every copy from a document; breaks parsing of ranges.
- What a correct application does
- Normalised before parsing, or accepted as an equivalent separator.
Capital i, lowercase L and one
look-alike-pairs/capital-i- 4 graphemes
- 4 code points
- 4 bytes
- 4 UTF-16 units
- What it breaks
- Capital i, lowercase L and the digit one in one value: indistinguishable in many typefaces.
- What a correct application does
- Displayed in a typeface where the characters can be told apart, wherever the value must be read back.
Letter O and digit zero
look-alike-pairs/digit-zero-letter-o- 2 graphemes
- 2 code points
- 2 bytes
- 2 UTF-16 units
- What it breaks
- The same problem for the letter O and the digit zero, in codes people retype by hand.
- What a correct application does
- Same as above, or the ambiguous characters excluded from generated codes.
Pairs
Each pair is two of the values above, worth typing side by side: into two fields, or into one field twice. AltShiftN types them in turn, and the palette says which half of a pair comes next.
Latin a against Cyrillic a
look-alike-pairs/latin-vs-cyrillic-a- What it breaks
- Two visually identical usernames become two accounts, and support cannot tell which is which.
- What a correct application does
- Either both accepted as distinct and shown as distinct, or the second rejected as a duplicate.
Latin o against Greek omicron
look-alike-pairs/latin-vs-greek-o- What it breaks
- Uniqueness checks that special-case one script miss the next one.
- What a correct application does
- Either both accepted as distinct and shown as distinct, or the second rejected as a duplicate.
Composed against decomposed accents
look-alike-pairs/nfc-vs-nfd- What it breaks
- The same name saved twice from two devices produces two records.
- What a correct application does
- Normalised on save, so both spellings end up as one record.
Ordinary space against non-breaking space
look-alike-pairs/space-vs-nbsppair 1 of 2 Name with an ordinary space
JanKowalski- 12 graphemes
- 12 code points
- 12 bytes
- 12 UTF-16 units
pair 2 of 2 Name with a non-breaking space
JanKowalski- 12 graphemes
- 12 code points
- 13 bytes
- 12 UTF-16 units
- What it breaks
- Search finds one and not the other, and nobody can see why.
- What a correct application does
- Both found by the same search, either because the space is normalised on save or because search treats both as a space.
Hyphen against en dash
look-alike-pairs/hyphen-vs-endash- What it breaks
- A range pasted from a document stops parsing, with no visible difference.
- What a correct application does
- Both forms parse as the same range, or the dash is normalised before parsing.