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.