2011-06-29 24 views
6

Primero desarrollo una biblioteca de plataforma independiente utilizando ANSI C (no C++ y ninguna biblioteca no estándar como MS CRT o glibc, ...).ANSI C UTF-8 problema

Después de algunas búsquedas, descubrí que una de las mejores formas de internacionalización en ANSI C es usar codificación UTF-8.

en UTF-8:

  • strlen (s): siempre cuenta el número de bytes .
  • mbstowcs (NULL, s, 0): Se puede contar el número de caracteres.

Pero tengo algunos problemas cuando quiero acceder aleatoriamente a los elementos (caracteres) de una cadena utf-8.

En la codificación ASCII:

char get_char(char* assci_str, int n) 
{ 
    // It is very FAST. 
    return assci_str[n]; 
} 

En UTF-16/32 de codificación:

wchar_t get_char(wchar_t* wstr, int n) 
{ 
    // It is very FAST. 
    return wstr[n]; 
} 

Y aquí mi problema en la codificación UTF-8:

// What is the return type? 
// Because sizeof(utf-8 char) is 8 or 16 or 24 or 32. 
/*?*/ get_char(char* utf8str, int n) 
{ 
    // I can found Nth character of string by using for. 
    // But it is too slow. 
    // What is the best way? 
} 

Gracias.

+1

¿Tiene un ejemplo de un caso en el que se usa "Nth character"? –

+0

'mbstowcs' no garantiza hacer lo que usted reclama. Depende de la configuración de tu configuración regional, mira '', y generalmente está codificado-agnóstico. Use 'iconv' o algo así si maneja codificaciones definidas. –

+0

@R: 'replace (char * str) {for (...) {... get_char (i) ...}' –

Respuesta

7

Quizás esté pensando en esto un poco erróneamente. UTF-8 es una codificación que es útil para serializar datos, p. escribiéndolo en un archivo o la red. Sin embargo, es una codificación muy poco trivial, y una cadena de puntos de código Unicode puede terminar en cualquier número de bytes codificados.

Lo que probablemente deba hacer, si desea manejar texto (dada su descripción), es almacenar primas, cadenas de ancho fijo internamente. Si va a Unicode (lo cual debería), necesita 21 bits por punto de código, por lo que el tipo integral más cercano es uint32_t. En resumen, almacena todas tus cadenas internamente como matrices de enteros. Luego puede acceder aleatoriamente a cada punto de código.

Codifique solamente a UTF-8 cuando está escribiendo en un archivo o consola, y decodifique desde UTF-8 al leer.

Por cierto, un punto de código Unicode todavía está muy lejos de un carácter. El concepto de un personaje está a muy alto nivel para tener una mecánica general simple. (Por ejemplo, "a" + "tumba de acento": dos puntos de código, ¿cuántos caracteres?)

+0

Sí, tiene razón, es mejor utilizar un carácter de tamaño fijo en lugar de utilizar la codificación de utf-8. Ahora quiero saber qué tipo es mejor para las cadenas UNICODE? whar_t o uint32_t? Mi respuesta es wchar_t. Pero es correcto o una selección incorrecta? –

+1

Incorrecto. Use 'uint32_t'. Su 'wchar_t' no viene con ninguna garantía de tamaño. Mira [mi reciente despotricar] (http://stackoverflow.com/questions/6300804/wchars-encodings-standards-and-portability) si tienes curiosidad sobre este tema en general. –

+0

¿Pero por qué Microsoft usa wchar_t para Unicode? –

4

Simplemente no puede. Si necesita muchas de estas consultas, puede crear un índice para la cadena UTF-8, o convertirlo a UTF-32 por adelantado. UTF-32 es una mejor representación en memoria, mientras que UTF-8 es bueno en el disco.

Por cierto, el código que listó para UTF-16 tampoco es correcto. Es posible que desee cuidar a los personajes sustitutos.

+0

UTF-32 es útil cuando necesita tratar con caracteres individuales. En la mayoría de los casos, no te importa, y solo deseas mover cadenas de un lado a otro, razón por la cual UTF-8 está muy extendido. – ninjalj

1

¿Qué desea contar? Como ha notado Kerrek SB, puede haber descompuesto los glifos, es decir, "é" puede representarse como un solo carácter (LATIN SMALL LETTER E WITH ACUTE U + 00E9), o como dos caracteres (LATIN SMALL LETER E U + 0065 COMBINING ACUTE ACCENT U + 0301). Unicode ha compuesto y descompuesto formas de normalización.

Lo que usted está probablemente interesado en el recuento no es caracteres, pero racimos de grafema. Necesita una biblioteca de nivel superior para manejar esto, y para tratar con formularios de normalización, colación adecuada (dependiente de la localidad), línea de corte adecuada, plegado de casos adecuado (por ejemplo, alemán ß-> SS), compatibilidad bidireccional adecuada, etc. .. Real I18N es complejo.

+1

Y las discusiones decentes de Unicode usan el "punto de código" donde tradicionalmente se puede usar "personaje" precisamente por este motivo: el equipaje histórico significa que el "personaje" también ambiguo cuando se quiere distinguir entre grafemas/glifos/clústeres de grafemas/ligaduras/... –

0

Al contrario de lo que otros han dicho, realmente no veo beneficio al usar UTF-32 en lugar de UTF-8: Al procesar texto, los conglomerados de grafemas (o 'caracteres percibidos por el usuario') son mucho más útiles que Unicode caracteres (es decir, puntos de código sin procesar), por lo que incluso UTF-32 debe tratarse como una codificación de longitud variable.

Si no desea utilizar una biblioteca dedicada, sugiero usar UTF-8 como en disco, representación endian-agnostic y UTF-8 modificado (que difiere de UTF-8 codificando el carácter cero como dos -byte sequence) como representación en memoria compatible con ASCIIZ.

La información necesaria para dividir cadenas en clústeres de grafema se puede encontrar en annex 29 y character database.