Meziantou.Framework.Unicode
2.0.4
Prefix Reserved
dotnet add package Meziantou.Framework.Unicode --version 2.0.4
NuGet\Install-Package Meziantou.Framework.Unicode -Version 2.0.4
<PackageReference Include="Meziantou.Framework.Unicode" Version="2.0.4" />
<PackageVersion Include="Meziantou.Framework.Unicode" Version="2.0.4" />
<PackageReference Include="Meziantou.Framework.Unicode" />
paket add Meziantou.Framework.Unicode --version 2.0.4
#r "nuget: Meziantou.Framework.Unicode, 2.0.4"
#:package Meziantou.Framework.Unicode@2.0.4
#addin nuget:?package=Meziantou.Framework.Unicode&version=2.0.4
#tool nuget:?package=Meziantou.Framework.Unicode&version=2.0.4
Meziantou.Framework.Unicode
This package provides Unicode helpers for normalizing confusable characters using the Unicode confusables table.
using Meziantou.Framework;
var input = "раураl"; // Uses Cyrillic letters that look like Latin
var normalized = Unicode.ReplaceConfusablesCharacters(input);
Console.WriteLine(normalized); // "paypal"
Detecting confusable strings
To decide whether two strings look alike, use the UTS #39
skeleton algorithm rather than comparing the output of ReplaceConfusablesCharacters:
Unicode.AreConfusable("paypal", "раураl"); // true (Cyrillic look-alikes)
Unicode.AreConfusable("café", "café"); // true (composed vs decomposed)
Unicode.AreConfusable("paypal", "example"); // false
Unicode.GetConfusableSkeleton(string) exposes the key itself, so it can be stored or indexed
to find collisions across a set of names:
var skeleton = Unicode.GetConfusableSkeleton(userName);
The skeleton is a comparison key, not displayable text. Do not show it to users or store it in place of the original string.
These two methods require Unicode normalization and therefore ICU. In globalization-invariant mode (
InvariantGlobalization=true)string.Normalizesilently does nothing, so they throwPlatformNotSupportedExceptionrather than return a result that would quietly fail to detect spoofing.
Detecting mixed-script text
A homograph attack usually shows up as a string that mixes writing systems. IsMixedScript
implements the UTS #39 resolved-script-set rules:
Unicode.IsMixedScript("paypal"); // false - all Latin
Unicode.IsMixedScript("раураl"); // true - Cyrillic letters with a Latin "l"
Unicode.IsMixedScript("日本語です"); // false - Japanese legitimately mixes Han and Hiragana
Unicode.IsMixedScript("user123"); // false - digits match any script
Script data is also exposed directly:
UnicodeScripts.GetScript(new Rune('A')); // UnicodeScript.Latin
UnicodeScripts.GetScript(new Rune(0x0410)); // UnicodeScript.Cyrillic
This package also exposes Unicode character metadata from the Unicode data table:
var info = Unicode.GetCharacterInfo(new Rune('A'));
if (info is not null)
{
Console.WriteLine(info.Value.Name); // "LATIN CAPITAL LETTER A"
Console.WriteLine(info.Value.Category); // UppercaseLetter
Console.WriteLine(info.Value.BidiCategory); // LeftToRight
Console.WriteLine(info.Value.Block); // BasicLatin
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net11.0 is compatible. |
-
net10.0
- No dependencies.
-
net11.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.4 | 57 | 9/8/2026 |
| 2.0.3 | 106 | 9/6/2026 |
| 2.0.2 | 151 | 8/29/2026 |
| 2.0.1 | 336 | 7/8/2026 |
| 2.0.0 | 129 | 7/5/2026 |
| 1.0.14 | 170 | 6/13/2026 |
| 1.0.13 | 134 | 6/7/2026 |
| 1.0.12 | 119 | 5/31/2026 |
| 1.0.11 | 137 | 5/17/2026 |
| 1.0.9 | 203 | 4/25/2026 |
| 1.0.8 | 224 | 2/15/2026 |
| 1.0.7 | 149 | 1/18/2026 |
| 1.0.5 | 143 | 1/16/2026 |
| 1.0.4 | 136 | 1/16/2026 |
| 1.0.2 | 132 | 1/16/2026 |
| 1.0.1 | 133 | 1/15/2026 |
| 1.0.0 | 136 | 1/15/2026 |