Unicode::Confusable
![[ci]](https://github.com/janlelis/unicode-confusable/workflows/Test/badge.svg)
Compares two strings if they are visually confusable as described in Unicode® Technical Standard #39: Both strings get transformed into a skeleton format before comparing them. The skeleton is generated by normalizing the string (NFD), removing ignorable characters, replacing confusable characters, and normalizing the string again.
Unicode version: 18.0.0 (September 2026)
* The Unicode normalization depends on your Ruby version
Please note: The TR39 standard now includes detection of confusables based on bidi formatting (i.e. right-to-left text). This is currently not supported by this gen.
Usage
Confusable?
require "unicode/confusable"
Unicode::Confusable.confusable? "a", "b" # => false
Unicode::Confusable.confusable? "C", "С" # => true
Unicode::Confusable.confusable? "ℜ𝘂ᖯʏ", "Ruby" # => true
Unicode::Confusable.confusable? "Michael", "Michae1" # => true
Unicode::Confusable.confusable? "⁇", "?" # => false
Unicode::Confusable.confusable? "⁇", "??" # => true
Skeleton
Unicode::Confusable.skeleton "ℜ𝘂ᖯʏ" # => "Ruby"
Please note: The skeleton is an intermediate representation, not meant for any other use than testing confusability, according to the standard.
List
List all characters that map to the confusable exemplar given:
Unicode::Confusable.list("o", false)
# => ["ం", "ಂ", "ം", "ං", "𑌂", "०", "০", "੦", "૦", "୦", "௦", "౦", "൦", "๐", "໐", "၀", "០", "᪀", "᪐", "𑓐", "٥", "۵", "o", "ℴ", "𝐨", "𝑜", "𝒐", "𝓸", "𝔬", "𝕠", "𝖔", "𝗈", "𝗼", "𝘰", "𝙤", "𝚘", "ᴏ", "ᴑ", "ꬽ", "ο", "𝛐", "𝜊", "𝝄", "𝝾", "𝞸", "σ", "𝛔", "𝜎", "𝝈", "𝞂", "𝞼", "ⲟ", "ϭ", "о", "ᲂ", "ჿ", "օ", "ס", "ه", "𞸤", "𞺄", "ﻫ", "ﻬ", "ﻪ", "ﻩ", "ھ", "ﮬ", "ﮭ", "ﮫ", "ﮪ", "ہ", "ﮨ", "ﮩ", "ﮧ", "ﮦ", "ە", "ࡀ", "ߋ", "ഠ", "ᯪ", "ဝ", "𐴇", "𑄤", "ᩅ", "𐓪", "ᄋ", "ㅇ", "ᄋ", "ᆼ", "𑣈", "𑣗", "𐤬", "𐐬"]
If you omit the second parameter, it will also show confusables, where the given character is just a part of:
Unicode::Confusable.list("o")
# => ["⒪", "㈇", "㈕", "㈝", "㈞", "ꜵ", "℅", "ꭃ", "ꭄ", "㏇", "ᴔ", "ꭁ", "ꭂ", "㏒", "ﷲ", "№", "ం", "ಂ", "ം", "ං", "𑌂", "०", "০", "੦", "૦", "୦", "௦", "౦", "൦", "๐", "໐", "၀", "០", "᪀", "᪐", "𑓐", "٥", "۵", "o", "ℴ", "𝐨", "𝑜", "𝒐", "𝓸", "𝔬", "𝕠", "𝖔", "𝗈", "𝗼", "𝘰", "𝙤", "𝚘", "ᴏ", "ᴑ", "ꬽ", "ο", "𝛐", "𝜊", "𝝄", "𝝾", "𝞸", "σ", "𝛔", "𝜎", "𝝈", "𝞂", "𝞼", "ⲟ", "ϭ", "о", "ᲂ", "ჿ", "օ", "ס", "ه", "𞸤", "𞺄", "ﻫ", "ﻬ", "ﻪ", "ﻩ", "ھ", "ﮬ", "ﮭ", "ﮫ", "ﮪ", "ہ", "ﮨ", "ﮩ", "ﮧ", "ﮦ", "ە", "ࡀ", "ߋ", "ഠ", "ᯪ", "ဝ", "𐴇", "𑄤", "ᩅ", "𐓪", "ᄋ", "ㅇ", "ᄋ", "ᆼ", "𑣈", "𑣗", "𐤬", "𐐬", "ۿ", "ة", "ﺔ", "ﺓ", "ۃ", "ø", "ꬾ", "ꚢ", "ɵ", "ꝋ", "ⲑ", "ө", "ѳ", "ꮎ", "ꮻ", "ꭴ", "ﮥ", "ﮤ", "ﳙ", "œ", "ɶ", "\u{1DF5E}", "𞹤", "∞", "ꝏ", "ꚙ", "ᅇ", "ㆀ", "ᇮ", "\u{1DF5F}", "㍵", "ѹ", "ﳗ", "ﱑ", "ﳘ", "ﱒ", "ﶓ", "ﶔ", "ﱓ", "ﱔ", "ൟ", "თ", "တ", "𑄖", "ᨲ", "ᅁ", "ᇬ", "ᇭ", "ᅂ", "ꥶ", "ᅃ", "ᅄ", "ᅅ", "ᇱ", "ㆂ", "ᅈ", "ᅉ", "ᇯ", "ᅊ", "ᅋ", "ꥷ", "ᅆ", "ᇲ", "ㆃ", "㏖", "ꭣ", "ﲠ", "ﳢ", "ﲥ", "ﳤ", "ﷻ", "𞱵", "ﴱ", "ﳨ", "ﴲ", "ﳪ", "ﷺ", "𞲱", "ﷷ", "𞲣", "ﳍ", "𞲟", "𞲞", "ﳖ", "ﳯ", "ﳞ", "ﳱ", "ﳦ", "ﲛ", "ﳠ", "ﯭ", "ﯬ", "ᄛ", "ퟝ", "ꥫ", "ᇕ", "ᄝ", "ㅱ", "ᇢ", "ᄫ", "ㅸ", "ᇦ", "ᄬ", "ㅹ", "ᄵ", "ퟫ", "ᅍ", "ᅗ", "ㆄ", "ᇴ", "ퟴ"]
No Bidi-Confusable Check
Testing for bidirectional confusables is currently not supported.
Single-script / Mixed-script / Whole-script
TR 39 also describes mechanisms for further categorization of confusables. This is currently not part of this gem, however the unicode-scripts gem does include mixed-script detection, which you can use for this purpose.
See unicode-x for more Unicode related micro libraries.
MIT License
- Copyright (C) 2016-2026 Jan Lelis https://janlelis.com. Released under the MIT license.
- Unicode data: https://www.unicode.org/copyright.html#Exhibit1