2009-09-03 5 views
18

Sto scrivendo una piccola applicazione in C che legge un semplice file di testo e quindi emette le righe una alla volta. Il problema è che il file di testo contiene caratteri speciali come Æ, Ø e Å, tra gli altri. Quando eseguo il programma nel terminale, l'output per quei caratteri è rappresentato da un "?".Gestione di caratteri speciali in C (codifica UTF-8)

C'è una soluzione facile?

risposta

28

prima cosa:

  1. lettura del buffer
  2. Uso libiconv o simili per ottenere tipo wchar_t da UTF-8 e utilizzando un'ampia funzioni movimentazione carattere come wprintf()
  3. Utilizza la funzioni di carattere ampio in C! La maggior parte delle funzioni di gestione file/output ha una variante a caratteri ampi

Assicurarsi che il terminale possa gestire l'uscita UTF-8. Avere la corretta impostazione della locale e manipolare i dati delle impostazioni locali può automatizzare molto l'apertura e la conversione dei file per te ... a seconda di cosa stai facendo.

Ricordare che la larghezza di un punto di codice o di un carattere in UTF-8 è variabile. Ciò significa che non puoi semplicemente cercare un byte e iniziare a leggere come con ASCII ... perché potresti atterrare nel mezzo di un punto di codice. Buone biblioteche possono farlo in alcuni casi.

Ecco il codice (non mia) che dimostra un certo uso della lettura UTF-8 file e carattere vasta manipolazione in C.

#include <stdio.h> 
#include <wchar.h> 
int main() 
{ 
    FILE *f = fopen("data.txt", "r, ccs=UTF-8"); 
    if (!f) 
     return 1; 

    for (wint_t c; (c = fgetwc(f)) != WEOF;) 
     printf("%04X\n", c); 

    fclose(f); 
    return 0; 
} 

Link

  1. libiconv
  2. Locale data in C/GNU libc
  3. Some handy info
  4. Another good Unicode/UTF-8 in C resource
+0

Grazie amico! Ci proverò ... – o01

+0

Nessun problema. Attaccalo, Unicode in C non è la cosa più semplice del mondo ... familiarizza anche con gli standard :) –

3

Assicurati di non perdere accidentalmente alcun byte; alcuni caratteri UTF-8 hanno una lunghezza superiore a un byte (è una specie di punto) e devi mantenerli tutti.

Può essere utile per stampare il contenuto del buffer come esadecimale, in modo da poter ispezionare cui i byte vengono effettivamente letti:

static void print_buffer(const char *buffer, size_t length) 
{ 
    size_t i; 

    for(i = 0; i < length; i++) 
    printf("%02x ", (unsigned int) buffer[i]); 
    putchar('\n'); 
} 

Si può fare questo dopo il caricamento di un file molto breve, che contiene solo alcuni personaggi.

Verificare inoltre che il terminale sia impostato sulla codifica corretta, in modo da interpretare i caratteri come UTF-8.

+0

Il mio terminale è impostato sulla codifica UTF-8. Il programma memorizza tutti i caratteri di ogni riga dal file di testo in un array di caratteri tramite fgets(); Se sto perdendo dei byte, non ho idea del perché o di come risolverlo ... (Sto solo iniziando ad imparare C btw) – o01

+0

@Eirik, non usare fgets() che è orientato ASCII. Usa fgetwc() dal mio post. –

2

Probabilmente il file di testo ha la certificazione ISO-8559-1 codifica ma il vostro terminale è UTF-8. Questo tipo di disallineamento è un problema standard quando si ha a che fare con la gestione del testo orientata ai byte; altri programmi C (come i comandi standard "cat" e "more") faranno la stessa cosa e generalmente non è considerato un errore o qualcosa che deve essere risolto.

Se si desidera operare su un livello di carattere Unicode invece di byte va bene, ma sarà necessario utilizzare wchar come tipo di carattere invece di char in tutto il programma, e fornire switch per l'utente per specificare quale sarà l'input la codifica del file è in realtà. (Mentre a volte è possibile indovinare, non è molto affidabile.)

2

Non so se potrebbe essere d'aiuto ma se sei sicuro che le codifiche di terminale e file di input sono le stesse, puoi provare a setlocale():

#include <locale.h> 
… 
setlocale(LC_CTYPE, ""); 
+0

Ho usato 'setlocale (LC_CTYPE," UTF-8 ");'. È stato necessario leggere il file con esito positivo anche se l'ambiente shell è stato configurato correttamente. – lkuty

+0

Con 'setlocale (LC_CTYPE," ")', ogni parte delle impostazioni locali che devono essere modificate viene impostata in base alle variabili di ambiente. – jgrocha

+0

Oh sì, mi dispiace, che avrebbe dovuto essere "" "' e non 'NULL'. –