Odstranění diakritiky z textu v C++ na Linuxu
3.1.2019
V minulém příspěvku jsem ukázal jak v C++ s využitím knihovny GLib snadno odstranit z textu diakritiku. Pokud z nějakého důvodu nechceme nebo nemůžeme v aplikaci použít knihovnu GLib (nebo nějaký jiný framework), použijeme v Linuxu přímo funkci iconv (a související). Jejich deklarace jsou v hlavičkovém souboru iconv.h.
Uvedu nejprve komplení kód ukázkové aplikace a pak pár vysvětlujících poznámek
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <locale.h> #include <iconv.h> #include <string> std::string iconv_impl(const char* text, bool zobraz = true) { if (zobraz) printf("%s\n", (char*)text); iconv_t ictd = iconv_open("ASCII//TRANSLIT", "UTF-8"); if ((iconv_t)-1 == ictd) { perror("chyba iconv_open"); return std::string(""); } size_t delka = strlen(text) * 2; char* vstup = (char*)malloc(delka); char* vystup = (char*)malloc(delka); char* vystup_orig = vystup; char* vstup_orig = vstup; size_t size_vstup = delka; size_t size_vystup = delka; strcpy(vstup, text); if (iconv(ictd, (char**) &vstup, &size_vstup, (char**)&vystup, &size_vystup) == (size_t)-1) { perror("chyba iconv"); iconv_close(ictd); free(vstup_orig); free(vystup_orig); return std::string(""); } if (zobraz) printf("%s\n", vystup_orig); std::string str_vystup = vystup_orig; iconv_close(ictd); free(vstup_orig); free(vystup_orig); return str_vystup; } int main(int argc, char** argv) { setlocale(LC_ALL, ""); std::string str = iconv_impl("Nějaký český text.€.$.@.ěščřžýáíé.#.ĚŠČŘŽÝÁÍÉ"); printf("pro kontrolu: %s\n", str.c_str()); return 0; }
Proč alokuji dvojnásobek délky vstupního textu?
Jak bude zřejmě při spuštění programu, (jeden) znak pro "euro" je ve výstupu (bez diakritiky) převeden na trojznakový text EUR. Podobně to může být i s jinými znaky (v jiných jazycích), proto tato "bezpečná velikost".
Proč ukládám ukazatele na alokovaná pole do proměnných vstup_orig a vystup_orig, které pak předávám jako parametry funkce free při uvolnění paměti?
Funkci iconv totiž předáváme jako parametry adresy ukazatelů (char**) a tato funkce ty ukazatele použije při procházení textovým polem a mění jejich hodnoty, takže po provedení funkce iconv máme v předaných proměnných jiné adresy než na vstupu. Funkce free samozřejmě vyžaduje adresu počátku bloku který má uvolnit, takže jí musíme předat právě ty předem uložené hodnoty.