2009-09-03 140 views
18

Escribo una pequeña aplicación en C que lee un archivo de texto simple y luego muestra las líneas una por una. El problema es que el archivo de texto contiene caracteres especiales como Æ, Ø y Å, entre otros. Cuando ejecuto el programa en el terminal, la salida de esos caracteres se representa con un "?".Manejo de caracteres especiales en C (codificación UTF-8)

¿Existe una solución fácil?

Respuesta

28

Lo primero es lo primero:

  1. leer el buffer de
  2. Uso libiconv o similares para obtener el tipo wchar_t de UTF-8 y utilizar la amplia las funciones de manipulación de caracteres tales como wprintf()
  3. uso del funciones de caracteres anchos en C! La mayoría de las funciones de manejo de archivos/salida tienen una variante de caracteres anchos

asegurarse de que su terminal de salida puede manejar UTF-8. Tener la configuración correcta de la configuración regional y manipular los datos de la configuración regional puede automatizar gran parte de la apertura y conversión del archivo para usted ... en función de lo que esté haciendo.

Recuerde que el ancho de un punto de código o carácter en UTF-8 es variable. Esto significa que no puedes simplemente buscar un byte y comenzar a leer como con ASCII ... porque podrías aterrizar en el medio de un punto de código. Las buenas bibliotecas pueden hacer esto en algunos casos.

Aquí hay un código (no la mía) que demuestra un cierto uso de la lectura UTF-8 archivo y el carácter amplio manejo en 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; 
} 

Enlaces

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

Gracias amigo! Probaré esto ... – o01

+0

Sin problemas. Adhiérete, Unicode en C no es la cosa más simple del mundo ... familiarízate también con los estándares :) –

3

Asegúrese de no caer accidentalmente ningún byte; algunos caracteres UTF-8 tienen más de un byte de longitud (ese es el tipo de punto), y necesitas mantenerlos todos.

Puede ser útil para imprimir el contenido de la memoria intermedia como hexagonal, por lo que puede inspeccionar el cual bytes realmente se lee:

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'); 
} 

Usted puede hacer esto después de cargar un archivo muy corta, que contiene sólo unos pocos caracteres.

También asegúrese de que el terminal esté configurado con la codificación adecuada, por lo que interpreta sus caracteres como UTF-8.

+0

Mi terminal está configurado para la codificación UTF-8. El programa almacena todos los caracteres de cada línea desde el archivo de texto en una matriz char mediante fgets(); Si estoy perdiendo bytes, no tengo idea de por qué o cómo solucionarlo ... (Empezando a aprender C por cierto) – o01

+0

@Eirik, no use fgets() que esté orientado a ASCII. Use fgetwc() de mi publicación. –

2

Probablemente su archivo de texto es codificado ISO-8559-1, pero su terminal es UTF-8. Este tipo de desajuste es un problema estándar cuando se trata de manejo de texto orientado a bytes; otros programas C (como los comandos estándar 'cat' y 'more') harán lo mismo y, en general, no se consideran un error o algo que deba corregirse.

Si desea operar en un nivel de carácter Unicode en lugar de bytes está bien, pero necesitará usar wchar como su tipo de carácter en lugar de char en su programa, y ​​proporcionar interruptores para que el usuario especifique lo que entra la codificación de archivo es en realidad. (Aunque a veces es posible adivinar, no es muy confiable.)

2

No sé si podría ayudar, pero si está seguro de que las codificaciones del terminal y del archivo de entrada son las mismas, puede intentar setlocale():

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

Utilicé 'setlocale (LC_CTYPE," UTF-8 ");'. Fue necesario leer el archivo con éxito, aunque el entorno del shell se configuró correctamente. – lkuty

+0

Con 'setlocale (LC_CTYPE," ")', cada parte de la configuración regional que se debe modificar se establece de acuerdo con las variables de entorno. – jgrocha

+0

Oh, sí, lo siento, debería haber sido '" "' y no 'NULL'. –