2011-01-03 15 views
5

Estoy intentando hacer mi propia versión de wc (filtro unix), pero tengo problemas con caracteres que no son ASCII. Hice un volcado HEX de un archivo de texto y descubrí que estos personajes ocupan más de un byte, por lo que no se ajustan a caracteres. ¿Hay alguna manera de cómo puedo leer estos caracteres del archivo y manejarlos como un solo carácter (para que pueda contar los caracteres en el archivo) en C? He estado buscando en Google un poco y encontré algún tipo de wchar_t, pero no había un simple ejemplo de cómo usarlo con los archivos.Manejo de caracteres multibyte (no ASCII) en C

+2

Necesitará conocer Unicode y, en particular, codificaciones. ¿Sabes lo que significan estos términos? –

+0

Además, es posible que desee conocer las codificaciones de bytes únicos no ASCII, como las distintas codificaciones ISO, Windows 1252, etc. Como ya sabrá, ASCII es en realidad una codificación de 7 bits de ancho. –

+0

@Joey gracias, tan acostumbrado a ASCII, ISO, ANSI, etc. ¡Forme un mal hábito! –

Respuesta

2

Go eche un vistazo a ICU. Esa biblioteca es lo que necesita para resolver todos los problemas.

8

He estado buscando en Google un poco y encontré algún tipo de wchar_t, pero no había un ejemplo simple de cómo usarlo con los archivos.

Bien conocido. No hubo ejemplos simples porque, desafortunadamente, el soporte adecuado del juego de caracteres no es   simple.

Aparte: en un mundo ideal, todo el mundo usaría UTF-8 (una codificación Unicode que es eficiente desde el punto de vista de la memoria, robusto y compatible con ASCII), la biblioteca C estándar incluiría decodificación de codificación UTF-8 apoyo, y la respuesta a esta pregunta (y tratar con el texto en general) sería simple y directa.

La respuesta a la pregunta "What is the best unicode library for C?" es utilizar la biblioteca ICU. Es posible que desee mirar ustdio.h, ya que tiene una función u_fgetc, y agregar soporte Unicode a su programa probablemente tome poco más que escribir u_ varias veces.

Además, si puede dedicar unos minutos a leer un poco, puede leer The Absolute Minimum Every Software Developer Absolutely, Positively Must Know about Unicode and Character Sets (No Excuses!) de Joel   en el software  .

I, UCI, personalmente, nunca se han utilizado, pero probablemente lo hará a partir de ahora :-)

+0

Me gustó mucho su: "El mínimo absoluto que todo desarrollador de software debe saber absolutamente sobre Unicode y conjuntos de caracteres (¡sin excusas!)". ¡Buena publicación!. – JosEduSol

4

Si desea escribir una versión estándar de C de la utilidad wc que respeta la configuración de idioma actual cuando se ejecuta , entonces puede usar las versiones wchar_t de las funciones stdio. Al inicio del programa, debe llamar setlocale():

setlocale(LC_CTYPE, ""); 

Esto hará que las funciones de caracteres anchos que utilizan el juego de caracteres correspondiente definido por el medio ambiente - por ejemplo. en sistemas tipo Unix, la variable de entorno LANG. Por ejemplo, esto significa que si su variable LANG está configurada en una configuración regional UTF8, las funciones de caracteres anchos manejarán las entradas y salidas en UTF8. (Así es como se especifica la utilidad POSIX wc para que funcione).

Puede usar las versiones de caracteres anchos de todas las funciones estándar. Por ejemplo, si tiene un código como este:

long words = 0; 
int in_word = 0; 
int c; 

while ((c = getchar()) != EOF) 
{ 
    if (isspace(c)) 
    { 
     if (in_word) 
     { 
      in_word = 0; 
      words++; 
     } 
    } 
    else 
    { 
     in_word = 1; 
    } 
} 

...que le convierte a la versión de caracteres anchos cambiando c a un wint_t, getchar() a getwchar(), EOF a WEOF y isspace()-iswspace():

long words = 0; 
int in_word = 0; 
wint_t c; 

while ((c = getwchar()) != WEOF) 
{ 
    if (iswspace(c)) 
    { 
     if (in_word) 
     { 
      in_word = 0; 
      words++; 
     } 
    } 
    else 
    { 
     in_word = 1; 
    } 
} 
+4

Es descortés votar sin un comentario explicativo. – caf

0

¿Seguro que realmente necesita el número de caracteres ? wc cuenta el número de bytes.

~$ echo 'דניאל' > hebrew.txt 
~$ wc hebrew.txt 
1 1 11 hebrew.txt 

(11 = 5 caracteres de dos bytes + 1 byte para '\ n')

Sin embargo, si realmente desea contar caracteres en lugar de bytes, y se puede asumir que los archivos de texto son codificado en UTF-8, entonces el enfoque más fácil es contar todos los bytes que son no bytes de camino (es decir, en el rango de 0x80 a 0xBF).

Si no puede asumir UTF-8, pero puede asumir que los archivos no UTF-8 están en una codificación de un solo byte, a continuación, realizar una comprobación de validación UTF-8 en los datos. Si pasa, devuelva la cantidad de bytes principales UTF-8. Si falla, devuelve la cantidad total de bytes.

(Tenga en cuenta que el enfoque anterior es específico para wc. Si en realidad estás haciendo algo con los personajes en lugar de contarlos, necesitará saber la codificación.)

+3

Tenga en cuenta que 'wc -m' en realidad cuenta * caracteres * en oposición a * bytes * -' wc -m hebrew.txt' da el resultado '6 hebrew.txt'. – caf

1

La mayoría de las respuestas hasta el momento tienen mérito, pero que se utiliza depende de la semántica que desee:

  • Si desea procesar texto en la codificación local configurado y no se preocupan por completo fracaso en el caso de encontrarse con secuencias no válidas , utilizando getwchar() está bien.
  • Si desea procesar el texto en la codificación de la configuración configurada, pero necesita detectar y recuperar secuencias no válidas, debe leer los bytes y usar mbrtowc manualmente.
  • Si siempre desea procesar texto como UTF-8, necesita leer bytes y alimentarlos a su propio decodificador. Si sabe de antemano que el archivo será UTF-8 válido, puede simplemente contar los bytes en los rangos 00-7F y C2-F4 y omitir el conteo de todos los demás bytes, pero esto podría dar resultados incorrectos en presencia de secuencias no válidas. Un enfoque más robusto sería descodificar la corriente de bits a los puntos de código Unicode y contar el número de decodificaciones exitosas.

Espero que esto ayude.

Cuestiones relacionadas