2011-01-05 19 views
9

Devo passare un po 'di testo e scrivere l'output UTF8 in base ai pattern di caratteri. Ho pensato che sarebbe stato facile poter lavorare con i punti di codice e convertirlo in UTF8. Ho letto di unicode e UTF8 ma non sono riuscito a trovare una buona soluzione. Qualsiasi aiuto sarà apprezzato.Libreria C per convertire i punti codice unicode in UTF8?

risposta

33

Conversione punti di codice Unicode UTF-8 è così banale che effettua la chiamata a una libreria probabilmente richiede più di un semplice codice di farlo da soli:

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; 

Inoltre, farlo da soli significa che è possibile sintonizzare l'API per il tipo di w hai bisogno di (carattere alla volta? O stringhe lunghe?) È possibile rimuovere i casi di errore se si sa che il proprio input è un valore scalare Unicode valido.

L'altra direzione è un po 'più difficile da correggere. Raccomando un approccio di automa finito piuttosto che i tipici loop di aritmetica dei bit che a volte decodificano sequenze non valide come alias per i personaggi reali (che è molto pericoloso e può portare a problemi di sicurezza).

Modifica: Anche se si finisce con una libreria, penso che si dovrebbe provare a scriverlo prima o almeno a studiare seriamente le specifiche UTF-8 prima di andare oltre. Un pessimo design può derivare dal considerare UTF-8 come una scatola nera quando il punto è che non è una scatola nera ma è stato creato per avere proprietà molto potenti, e troppi programmatori nuovi a UTF-8 non riescono a vederlo fino a quando hanno lavorato molto con loro stessi.

+6

@Philipp: sta scrivendo più codice per racchiudere una libreria in modo che corrisponda alle esigenze dell'interfaccia e aggirare meglio i suoi bug? Se ti interessa sfogliare il codice della libreria esistente che decodifica UTF-8, scoprirai che la stragrande maggioranza è sbagliata in modi almeno impercettibili, e almeno il 30% ha seri bug critici per la sicurezza. (Queste stime provengono da una ricerca sul codice di Google che ho fatto un po 'di tempo fa.) Inoltre, l'implementazione GNU di 'iconv' è di ordine di grandezza troppo lento per le conversioni carattere-a-tempo, sebbene funzioni correttamente (anche se con non conformità intenzionale) per le conversioni di massa. –

+0

il mio scatto a una versione più avanzata: http://mercurial.intuxication.org/hg/cstuff/raw-file/tip/utf8_encode.c – Christoph

+2

Rifiutare non caratteri può essere utile per la tua applicazione, ma non fa parte del Specifica UTF-8 e in generale errata. Le UTF sono mappe uno-a-uno tra sequenze di unità di codice (byte o parole più grandi) e "Valori scalari Unicode". I valori scalari Unicode sono esattamente gli interi 0-0xD7FF e 0xE000-0x10FFFF. Questo è tutto definito nello standard Unicode che dovresti leggere prima di provare a implementare qualcosa di tuo. –

1

Quale piattaforma? Su Windows, è possibile utilizzare WideCharToMultiByte (CP_UTF8, ...)

Probabilmente, il codice sorgente deve essere codificato in UTF-16, il che significa che si deve essere in grado di eseguire tale codifica. In alcuni casi (coppie surrogate), non è banale.

La mia comprensione è che si dispone di un testo in una determinata tabella codici e si desidera convertirlo in Unicode (UTF-16). Destra? Un roundtrip MultiByteToWideChar (codePage, sourceText, ...)/WideCharToMultiByte (CP_UTF8, utf16Text, ...) farà il trucco.

+0

Sto lavorando su linux. – chanux

+0

@chanux: Quindi puoi usare 'iconv', come descritto nelle altre risposte. – Philipp

5

iconv potrebbe essere utilizzato I 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); 

ma temo che wchar_t potrebbero non rappresentare i punti di codice Unicode, ma valori arbitrari .. EDIT: Credo che si può farlo semplicemente utilizzando una fonte Unicode:

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

Cosa succede se il punto di codice non si trova nel BMP? ucs-2 non può rappresentarlo. Un wchar_t potrebbe non essere sufficiente secondo la piattaforma. Questo è il motivo per cui penso che l'ipotesi dell'OP sulla conoscenza del punto di codice sia errata. Perché allora viene posta la domanda della codifica utilizzata per rappresentarla (UTF-32? UTF-16? Ovviamente non UTF-8) –

+1

Se '__STDC_ISO_10646__' è definito,' wchar_t' è un valore di punto di codice Unicode. Si noti che se 'wchar_t' è 16-bit, ciò implica che solo il BMP è supportato; UTF-16 non è una possibilità. –

+1

Un 'wchar_t' a 16 bit può essere definitivamente utilizzato nelle stringhe codificate UTF-16. Tutto ciò significa che qualsiasi valore di codepoint al di fuori del BMP verrà codificato usando 2 'wchar_t' per i caratteri affiancati nella stringa codificata, tutto qui. L'API di Windows funziona esattamente su questo tipo di dati e funziona perfettamente. –

Problemi correlati