Normalization

edit

Normalize a text

The same text can be written with different code points: é is one code point, or an e followed by a combining acute accent. Normalization gives one form to texts that are the same, so that you can compare them, use them as keys, or search them. UnicodeNormalization implements the four forms of UAX #15:

Assert.Equal("caf\u00E9", UnicodeNormalization.Normalize("cafe\u0301")); // NFC
Assert.Equal("cafe\u0301", UnicodeNormalization.Normalize("caf\u00E9", NormalizationForm.FormD));
Assert.True(UnicodeNormalization.IsNormalized("caf\u00E9"));

// Span-based
Span<char> destination = stackalloc char[16];
Assert.True(UnicodeNormalization.TryNormalize("cafe\u0301", destination, out var written));
Assert.Equal("caf\u00E9", destination[..written]);

Assert.True(UnicodeNormalization.TryComposeCanonical('e', 0x0301, out var composite));
Assert.Equal('\u00E9', composite);

Unlike string.Normalize, the results do not depend on the globalization library of the platform: they are the same everywhere, including in globalization-invariant mode, where string.Normalize only handles ASCII.

Choose a form

FormWhat it doesUse it for
NFC (FormC)Composes charactersStoring and exchanging text
NFD (FormD)Decomposes charactersProcessing letters and their accents separately
NFKC (FormKC)Composes, and replaces the characters that differ only by their presentationIdentifiers, search keys
NFKD (FormKD)Decomposes, and replaces the characters that differ only by their presentationSearch keys; remove the combining marks afterwards to ignore accents

The compatibility forms (NFKC and NFKD) lose information: a ligature becomes its letters, a superscript a plain digit. Use them for comparison keys, not to store the text a user typed:

// NFKC also replaces the characters that differ only by their presentation
Assert.Equal("fi", UnicodeNormalization.Normalize("\uFB01", NormalizationForm.FormKC)); // the "fi" ligature
Assert.Equal("x2", UnicodeNormalization.Normalize("x\u00B2", NormalizationForm.FormKC)); // a superscript two
Assert.Equal("ABC", UnicodeNormalization.Normalize("\uFF21\uFF22\uFF23", NormalizationForm.FormKC)); // full-width letters

// NFC keeps them
Assert.Equal("\uFB01", UnicodeNormalization.Normalize("\uFB01"));