Jak spolehlivě odstranit v .NET z řetězce diakritiku

Již léta opakuji, kdykoliv přijde řeč na česká "nabodeníčka", že Jana Husa upálili po právu a bohužel pozdě. Historicky se většina pokroku v počítačových technologiích odehrávala v anglosaských zemích. Národy, mající ve zvyku okrašlovat nudná písmenka háčky, čárkami, ocásky a podobně jsou tedy v řadě případů poněkud diskriminovány.

V praxi často nastává situace, kdy je třeba z nějakého textu odstranit písmenka s háčky a čárkami. A to pokud možno tak, aby se tato písmena neztratila, ale byla převedena na "neokrášlené" ekvivalenty, aby text zůstal i nadále čitelný. Řešení tohoto úkolu je složitější, než na první pohled vypadá.

První co většinu programátorů napadne, je vytvořit seznam písmen s diakritikou a jemu odpovídajících písmen bez háčků a čárek. Toto řešení není zcela špatné - a ve verzích 1.x je pokud vím jediné možné. Záludnost tohoto řešení spočívá v tom, že onen seznam písmen zpravidla vzniká tak, že se programátor hluboce zamyslí a napíše něco jako "äáčďéěëíňóöřšťůúüýž". Jenomže rozličnými přívěsky okrášlených písmenek je mnohem víc, než si většina z nás myslí. Stačí se podívat na Slovensko a písmenka jako Ľ nebo Ĺ.

Naštěstí pro nás umí .NET ve verzi 2.0 pracovat s takzvanými Unicode kategoriemi. Unicode je sada norem, které si vzaly za cíl učinit počítače použitelnými pro včechny jazyky a definitivně zlomit prokletí původně osmibitové znakové sady.

Jedním z prostředků je zakódování textu tak, že se oddělí "mateřské" písmeno a jeho modifikátor. Je to trochu jako když jste na starém mechanickém psacím stroji chtěli napsat velké písmeno s háčkem: nejdříve jste na papíře vytvořili háček a pak pod něj dodali písmenko. A přesně této funkce nyní využijeme:

// using System.Globalization

public static string RemoveDiacritics(string s) {

    s = s.Normalize(NormalizationForm.FormD);

    StringBuilder sb = new StringBuilder();

 

    for (int i = 0; i < s.Length; i++) {

        if (CharUnicodeInfo.GetUnicodeCategory(s[i]) != UnicodeCategory.NonSpacingMark) sb.Append(s[i]);

    }

 

    return sb.ToString();

}

Pomocí metody Normalize převedeme náš řetězec právě do shora popsané podoby. Následně pak projdeme všechny znaky v řetězci a ponecháme si pro další použití jenom ty, které nejsou typu NonSpacingMark, což jsou právě naše nabodeníčka. V závislosti na požadované aplikaci lze samozřejmě konkrétně určit, jaké že Unicode kategorie mají být odstraněny či zachovány.

  • Altairis
  • Nemesis
  • Microsoft MVP
  • IIS
  • ASP.NET