Julien Chomarat
Dans le cadre d'un projet en cours, j'ai été amené à normaliser des chaînes de caractères pour en faciliter la recherche.
Avant de commencer, en C#, les chaînes de caractères sont par défaut Unicode et sous la forme NFC.
Les chaînes Unicodes peuvent être représentées sous 4 formes, NFC, NFD, NFKC et NFKD.
Dans notre cas, nous allons uniquement parler des formes NFC et NFD. Sur l'image ci-dessous, nous avons deux exemples de caractères accentués.
Comme nous pouvons le voir, la différence entre les deux représentations est que dans la forme NFD chaque lettre est décomposée par sa lettre de base et on y associe sa diacritique.
La lettre de base peut avoir la catégorie UnicodeCategory.UppercaseLetter
ou UnicodeCategory.LowercaseLetter
.<br /> Les accents ont la catégorie UnicodeCategory.NonSpacingMark
.
Si on reprend tout ça en code C# voilà le petit helper qui fait bien l'affaire:
using System.Globalization;
using System.Text;
public static class StringHelpers
{
public static string NormalizeString(this string str)
{
if (string.IsNullOrWhiteSpace(str))
return str;
// On transforme notre chaîne Unicode NFC en NFD
str = str.Normalize(NormalizationForm.FormD);
// On récupère tous les caractères sauf les diacritiques
var chars = str.Where(c => CharUnicodeInfo.GetUnicodeCategory(c) !=
UnicodeCategory.NonSpacingMark).ToArray();
// On retransforme la nouvelle chaîne Unicode NFD en NFC
return new string(chars).Normalize(NormalizationForm.FormC);
}
}
Dernier point important, pensez à toujours remettre votre chaîne de caractères en forme NFC. Sinon vous pourrez avoir des surprises lors de comparaisons de chaînes:
void Main()
{
string nfc = "Sébastien";
string nfd = nfc.Normalize(NormalizationForm.FormD);
Console.WriteLine($"NFC: {nfc}");
Console.WriteLine($"NFD: {nfd}");
Console.WriteLine($"Equals: {nfc == nfd}");
}
Dans la console vous verrez:
NFC: Sébastien
NFD: Sébastien
Equals: False