Existe-t-il un moyen de convertir UTF8 en iso-8859-1?

Mon logiciel reçoit des chaînes en UTF8 que je n’ai pas besoin de convertir en ISO 8859 1. Je sais que le domaine UTF8 est plus grand que ISO 8859. Mais les données en UTF8 ont été précédemment converties d’ISO, donc je ne devrais rien manquer.

Je voudrais savoir s’il existe un moyen facile / direct de convertir UTF8 en iso-8859-1.

Merci

Voici une fonction que vous pourriez trouver utile: utf8_to_latin9() . Il se convertit en ISO-8859-15 (y compris EURO, ce que ISO-8859-1 n’a pas), mais fonctionne également correctement pour la partie conversion UTF-8 -> ISO-8859-1 d’un ISO-8859-1 -> UTF-8 -> aller-retour ISO-8859-1 .

La fonction ignore les points de code invalides similaires à //IGNORE flag pour iconv, mais ne recompose pas les séquences UTF-8 décomposées; c’est-à-dire que U+006E U+0303 ne deviendra pas U+00F1 . Je ne prend pas la peine de recomposer car iconv non plus.

La fonction fait très attention à l’access à la chaîne. Il ne numérisera jamais au-delà du tampon. Le tampon de sortie doit avoir un octet de plus que la longueur, car il ajoute toujours l’octet NUL de fin de chaîne. La fonction renvoie le nombre de caractères (octets) en sortie, sans inclure l’octet NUL de fin de chaîne.

 /* 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); } 

Notez que vous pouvez append une translittération personnalisée pour des points de code spécifiques dans la fonction to_latin9() , mais vous êtes limité aux remplacements à un caractère.

Comme il est actuellement écrit, la fonction peut effectuer une conversion sur place en toute sécurité: les pointeurs d’entrée et de sortie peuvent être identiques. La chaîne de sortie ne sera jamais plus longue que la chaîne d'entrée. Si votre chaîne d'entrée peut contenir un octet supplémentaire (par exemple, si la chaîne de caractères NUL termine la chaîne), vous pouvez utiliser la fonction ci-dessus en toute sécurité pour la convertir de UTF-8 à ISO-8859-1 / 15. Je l'ai délibérément écrit de cette façon, car cela devrait vous éviter des efforts dans un environnement embarqué, bien que cette approche soit un peu limitée. personnalisation et extension.

Modifier:

J'ai inclus une paire de fonctions de conversion dans une édition de cette réponse pour la conversion Latin-1/9 vers / de UTF-8 (ISO-8859-1 ou -15 vers / depuis UTF-8); La principale différence est que ces fonctions renvoient une copie allouée dynamicment et conservent la chaîne d'origine intacte.

iconv – effectue la conversion du jeu de caractères

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 est "ISO_8859-1" et le fromcode est "UTF-8" .

Exemple de travail:

 #include  #include  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; }