GNU/Linux >> Znalost Linux >  >> Linux

Existuje způsob, jak převést z UTF8 na ISO-8859-1?

Zde je funkce, která by se vám mohla hodit:utf8_to_latin9() . Převede se na ISO-8859-15 (včetně EURO, které ISO-8859-1 nemá), ale také funguje správně pro UTF-8 ->ISO-8859-1 část konverze ISO-8859-1 ->UTF-8 ->ISO-8859-1 zpáteční cesta.

Funkce ignoruje neplatné kódové body podobné //IGNORE příznak pro iconv, ale nerozkládá rozložené sekvence UTF-8; to znamená, že se to nezmění na U+006E U+0303 do U+00F1 . Neobtěžuji se překomponováním, protože iconv také ne.

Funkce je velmi opatrná na přístup k řetězcům. Nikdy nebude skenovat za vyrovnávací paměť. Výstupní vyrovnávací paměť musí být o jeden bajt delší, než je délka, protože vždy připojuje bajt NUL na konci řetězce. Funkce vrací počet znaků (bajtů) ve výstupu, nezahrnuje bajt NUL na konci řetězce.

/* UTF-8 to ISO-8859-1/ISO-8859-15 mapper.
 * Return 0..255 for valid ISO-8859-15 code points, 256 otherwise.
*/
static inline unsigned int to_latin9(const unsigned int code)
{
    /* Code points 0 to U+00FF are the same in both. */
    if (code < 256U)
        return code;
    switch (code) {
    case 0x0152U: return 188U; /* U+0152 = 0xBC: OE ligature */
    case 0x0153U: return 189U; /* U+0153 = 0xBD: oe ligature */
    case 0x0160U: return 166U; /* U+0160 = 0xA6: S with caron */
    case 0x0161U: return 168U; /* U+0161 = 0xA8: s with caron */
    case 0x0178U: return 190U; /* U+0178 = 0xBE: Y with diaresis */
    case 0x017DU: return 180U; /* U+017D = 0xB4: Z with caron */
    case 0x017EU: return 184U; /* U+017E = 0xB8: z with caron */
    case 0x20ACU: return 164U; /* U+20AC = 0xA4: Euro */
    default:      return 256U;
    }
}

/* Convert an UTF-8 string to ISO-8859-15.
 * All invalid sequences are ignored.
 * Note: output == input is allowed,
 * but   input < output < input + length
 * is not.
 * Output has to have room for (length+1) chars, including the trailing NUL byte.
*/
size_t utf8_to_latin9(char *const output, const char *const input, const size_t length)
{
    unsigned char             *out = (unsigned char *)output;
    const unsigned char       *in  = (const unsigned char *)input;
    const unsigned char *const end = (const unsigned char *)input + length;
    unsigned int               c;

    while (in < end)
        if (*in < 128)
            *(out++) = *(in++); /* Valid codepoint */
        else
        if (*in < 192)
            in++;               /* 10000000 .. 10111111 are invalid */
        else
        if (*in < 224) {        /* 110xxxxx 10xxxxxx */
            if (in + 1 >= end)
                break;
            if ((in[1] & 192U) == 128U) {
                c = to_latin9( (((unsigned int)(in[0] & 0x1FU)) << 6U)
                             |  ((unsigned int)(in[1] & 0x3FU)) );
                if (c < 256)
                    *(out++) = c;
            }
            in += 2;

        } else
        if (*in < 240) {        /* 1110xxxx 10xxxxxx 10xxxxxx */
            if (in + 2 >= end)
                break;
            if ((in[1] & 192U) == 128U &&
                (in[2] & 192U) == 128U) {
                c = to_latin9( (((unsigned int)(in[0] & 0x0FU)) << 12U)
                             | (((unsigned int)(in[1] & 0x3FU)) << 6U)
                             |  ((unsigned int)(in[2] & 0x3FU)) );
                if (c < 256)
                    *(out++) = c;
            }
            in += 3;

        } else
        if (*in < 248) {        /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
            if (in + 3 >= end)
                break;
            if ((in[1] & 192U) == 128U &&
                (in[2] & 192U) == 128U &&
                (in[3] & 192U) == 128U) {
                c = to_latin9( (((unsigned int)(in[0] & 0x07U)) << 18U)
                             | (((unsigned int)(in[1] & 0x3FU)) << 12U)
                             | (((unsigned int)(in[2] & 0x3FU)) << 6U)
                             |  ((unsigned int)(in[3] & 0x3FU)) );
                if (c < 256)
                    *(out++) = c;
            }
            in += 4;

        } else
        if (*in < 252) {        /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
            if (in + 4 >= end)
                break;
            if ((in[1] & 192U) == 128U &&
                (in[2] & 192U) == 128U &&
                (in[3] & 192U) == 128U &&
                (in[4] & 192U) == 128U) {
                c = to_latin9( (((unsigned int)(in[0] & 0x03U)) << 24U)
                             | (((unsigned int)(in[1] & 0x3FU)) << 18U)
                             | (((unsigned int)(in[2] & 0x3FU)) << 12U)
                             | (((unsigned int)(in[3] & 0x3FU)) << 6U)
                             |  ((unsigned int)(in[4] & 0x3FU)) );
                if (c < 256)
                    *(out++) = c;
            }
            in += 5;

        } else
        if (*in < 254) {        /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
            if (in + 5 >= end)
                break;
            if ((in[1] & 192U) == 128U &&
                (in[2] & 192U) == 128U &&
                (in[3] & 192U) == 128U &&
                (in[4] & 192U) == 128U &&
                (in[5] & 192U) == 128U) {
                c = to_latin9( (((unsigned int)(in[0] & 0x01U)) << 30U)
                             | (((unsigned int)(in[1] & 0x3FU)) << 24U)
                             | (((unsigned int)(in[2] & 0x3FU)) << 18U)
                             | (((unsigned int)(in[3] & 0x3FU)) << 12U)
                             | (((unsigned int)(in[4] & 0x3FU)) << 6U)
                             |  ((unsigned int)(in[5] & 0x3FU)) );
                if (c < 256)
                    *(out++) = c;
            }
            in += 6;

        } else
            in++;               /* 11111110 and 11111111 are invalid */

    /* Terminate the output string. */
    *out = '\0';

    return (size_t)(out - (unsigned char *)output);
}

Všimněte si, že můžete přidat vlastní transliteraci pro konkrétní body kódu v to_latin9() funkce, ale jste omezeni na nahrazení jedním znakem.

Jak je aktuálně napsáno, funkce může bezpečně provádět konverzi na místě:vstupní a výstupní ukazatele mohou být stejné. Výstupní řetězec nebude nikdy delší než vstupní řetězec. Pokud má váš vstupní řetězec místo pro bajt navíc (například má NUL ukončující řetězec), můžete bezpečně použít výše uvedenou funkci k převodu z UTF-8 na ISO-8859-1/15. Záměrně jsem to napsal takto, protože by vám to mělo ušetřit určité úsilí ve vestavěném prostředí, i když tento přístup je trochu omezený. přizpůsobení a rozšíření.

Upravit:

Do úpravy této odpovědi jsem zahrnul dvojici konverzních funkcí pro převod Latin-1/9 do/z UTF-8 (ISO-8859-1 nebo -15 do/z UTF-8); hlavní rozdíl je v tom, že tyto funkce vracejí dynamicky alokovanou kopii a ponechávají původní řetězec nedotčený.


iconv - provedení konverze znakové sady

size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);

iconv_t iconv_open(const char *tocode, const char *fromcode);

tocode je "ISO_8859-1" a fromcode je "UTF-8" .

Pracovní příklad:

#include <iconv.h>
#include <stdio.h>

int main (void) {
    iconv_t cd = iconv_open("ISO_8859-1", "UTF-8");
    if (cd == (iconv_t) -1) {
        perror("iconv_open failed!");
        return 1;
    }

    char input[] = "Test äöü";
    char *in_buf = &input[0];
    size_t in_left = sizeof(input) - 1;

    char output[32];
    char *out_buf = &output[0];
    size_t out_left = sizeof(output) - 1;

    do {
        if (iconv(cd, &in_buf, &in_left, &out_buf, &out_left) == (size_t) -1) {
            perror("iconv failed!");
            return 1;
        }
    } while (in_left > 0 && out_left > 0);
    *out_buf = 0;

    iconv_close(cd);

    printf("%s -> %s\n", input, output);
    return 0;
}

Linux
  1. Existuje jednoduchý způsob, jak přesunout/zkopírovat logický svazek z jedné skupiny svazků do druhé? (LVM2)

  2. Existuje nějaký nástroj na vytváření prázdných obrázků?

  3. Existuje způsob, jak spustit vim v režimu pouze pro čtení

  1. Existuje způsob, jak obnovit přerušený scp souboru?

  2. Existuje způsob, jak restartovat špatné bloky?

  3. Existuje způsob, jak zkopírovat text v htop?

  1. Existuje způsob, jak povolit minicom linewrap ve výchozím nastavení

  2. Existuje způsob, jak změnit ID svazku souborů .iso z příkazového řádku?

  3. Existuje způsob, jak vyloučit konkrétní hostitele z hostitelské skupiny Nagios?