2011-01-05 1 views
9

Je dois passer par du texte et écrire une sortie UTF8 selon les modèles de caractères. Je pensais que ce serait facile si je pouvais travailler avec les points de code et le convertir en UTF8. J'ai lu sur unicode et UTF8 mais je n'ai pas trouvé une bonne solution. Toute aide serait appréciée.Bibliothèque C pour convertir les points de code Unicode en UTF8?

Répondre

33

Conversion des points de code Unicode UTF-8 est si trivial que faire appel à une bibliothèque prend probablement plus de code que simplement faire vous-même:

if (c<0x80) *b++=c; 
else if (c<0x800) *b++=192+c/64, *b++=128+c%64; 
else if (c-0xd800u<0x800) goto error; 
else if (c<0x10000) *b++=224+c/4096, *b++=128+c/64%64, *b++=128+c%64; 
else if (c<0x110000) *b++=240+c/262144, *b++=128+c/4096%64, *b++=128+c/64%64, *b++=128+c%64; 
else goto error; 

en outre, faire vous-même signifie que vous pouvez régler le api du type de w ork dont vous avez besoin (personnage à la fois? Ou chaînes longues?) Vous pouvez supprimer les cas d'erreur si vous savez que votre entrée est une valeur scalaire Unicode valide.

L'autre direction est un peu plus difficile à obtenir. Je recommande une approche d'automate fini plutôt que les boucles arithmétiques typiques qui décodent parfois des séquences invalides comme des alias pour des caractères réels (ce qui est très dangereux et peut entraîner des problèmes de sécurité).

Éditer: Même si vous finissez avec une bibliothèque, je pense que vous devriez soit essayer de l'écrire vous-même, soit au moins sérieusement étudier la spécification UTF-8 avant d'aller plus loin. Le traitement de l'UTF-8 en tant que boîte noire peut être une mauvaise idée car il ne s'agit pas d'une boîte noire, mais de trop de propriétés, et trop de programmeurs en UTF-8 ne le voient pas avant ils ont beaucoup travaillé avec eux.

+6

@Philipp: Est-ce que écrire plus de code pour envelopper une bibliothèque pour répondre aux besoins de votre interface et mieux contourner ses bogues? Si vous souhaitez parcourir le code de bibliothèque existant qui décode l'UTF-8, vous constaterez que la grande majorité d'entre eux est erronée, au moins de manière subtile, et au moins 30% ont de graves bogues critiques pour la sécurité. (Ces estimations proviennent d'une recherche de code Google que j'ai effectuée il y a quelques temps.) De plus, l'implémentation GNU de 'iconv' est trop lente pour les conversions caractère par caractère, bien que cela fonctionne bien (bien que cela ne soit pas intentionnel) pour les conversions en masse. –

+0

mon tir à une version plus avancée: http://mercurial.intuxication.org/hg/cstuff/raw-file/tip/utf8_encode.c – Christoph

+2

Rejeter des non-caractères peut être utile pour votre application, mais il ne fait pas partie de la Spécification UTF-8 et en général incorrecte. Les UTF sont des mappages un-à-un entre des séquences d'unités de code (octets ou mots plus grands) et des «valeurs scalaires Unicode». Les valeurs scalaires Unicode sont exactement les entiers 0-0xD7FF et 0xE000-0x10FFFF. Tout cela est défini dans la norme Unicode que vous devriez lire avant d'essayer de mettre en œuvre quelque chose de votre choix. –

1

Quelle plateforme? Sous Windows, vous pouvez utiliser WideCharToMultiByte (CP_UTF8, ...)

Vous pouvez argumenter que le code source doit être codé en UTF-16, ce qui signifie que vous devez pouvoir effectuer un tel encodage. Dans certains cas (paires de substitution), ce n'est pas trivial.

Je crois comprendre que vous avez du texte dans une page de codes donnée et que vous voulez le convertir en Unicode (UTF-16). Droite? Un tour MultiByteToWideChar (codePage, sourceText, ...)/WideCharToMultiByte (CP_UTF8, utf16Text, ...) fera l'affaire.

+0

Je travaille sur Linux. – chanux

+0

@chanux: Ensuite, vous pouvez utiliser 'iconv', comme décrit dans les autres réponses. – Philipp

5

iconv pourrait être utilisé Je figure.

#include <iconv.h> 

iconv_t cd; 
char out[7]; 
wchar_t in = CODE_POINT_VALUE; 
size_t inlen = sizeof(in), outlen = sizeof(out); 

cd = iconv_open("utf-8", "wchar_t"); 
iconv(cd, (char **)&in, &inl, &out, &outlen); 
iconv_close(cd); 

Mais je crains que wchar_t pourrait ne pas représenter les points de code Unicode, mais les valeurs arbitraires .. EDIT: Je suppose que vous pouvez le faire en utilisant simplement une source Unicode:

uint16_t in = UNICODE_POINT_VALUE; 
cd = iconv_open("utf-8", "ucs-2"); 
+2

Que faire si le point de code n'est pas dans le BMP? ucs-2 ne peut pas le représenter. Un wchar_t peut ne pas être suffisant selon la plate-forme. C'est pourquoi je pense que l'hypothèse du PO concernant la connaissance du point de code est fausse. Car alors, la question du codage utilisé pour le représenter est posée (UTF-32? UTF-16? Évidemment pas UTF-8) –

+1

Si '__STDC_ISO_10646__' est défini,' wchar_t' est une valeur de codepoint Unicode. Notez que si wchar_t est en 16 bits, cela implique que seul le BMP est supporté; UTF-16 n'est pas une possibilité. –

+1

Un 'wchar_t' de 16 bits peut certainement être utilisé dans les chaînes encodées en UTF-16. Tout ce que cela signifie est que n'importe quelle valeur de code en dehors de la BMP sera encodée en utilisant 2 caractères de substitution 'wchar_t' côte à côte dans la chaîne encodée, c'est tout. L'API Windows fonctionne exactement sur ce type de données, et cela fonctionne très bien. –

Questions connexes