Radek Chalupa   konzultace a školení programování, vývoj software na zakázku

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.