2012-08-20 36 views
9

Estoy escribiendo un programa que necesita poder trabajar con texto en todos los idiomas. Tengo entendido que UTF-8 hará el trabajo, pero estoy experimentando algunos problemas con él.UTF-8 Compatibilidad en C++

¿Tengo derecho a decir que UTF-8 se puede almacenar en un simple char en C++? Si es así, ¿por qué recibo la siguiente advertencia cuando uso un programa con char, string y stringstream: warning C4566: character represented by universal-character-name '\uFFFD' cannot be represented in the current code page (1252). (No obtengo ese error cuando uso wchar_t, wstring y wstringstream.)

Además, sé que UTF es de longitud variable. Cuando uso los métodos de cadena at o substr, ¿obtendría la respuesta incorrecta?

+0

Para UTF wchar_t es el almacenamiento recomendado. Puede almacenar UTF-8 sin problemas pero los resultados serán extraños. – perilbrain

+4

@ Anónimo que depende de su plataforma (y del * qué * sabor de UTF que le interese). En Windows, 'wchar_t' es una buena opción para UTF-16. En Linux, es apropiado usarlo para UTF-32. Para UTF-8, 'char' es un candidato bastante razonable (a menos que tenga acceso a los tipos de caracteres" nuevos "en C++ 11) – jalf

+0

Este programa se transportará a través de plataformas. ¿Qué tipo de carácter se puede usar mejor para ese propósito? – Qman

Respuesta

11

para utilizar UTF-8 literales de cadena que necesita usar el prefijo con u8, de otro modo se obtiene el conjunto de caracteres de la aplicación (en su caso, parece ser Windows-1252): u8"\uFFFD" es la secuencia de terminación nula de bytes con el Representación UTF-8 del carácter de reemplazo (U + FFFD). Tiene tipo char const[4].

Dado que UTF-8 tiene longitud variable, todos los tipos de indexación indexarán en unidades de código, no en puntos de código. No es posible hacer acceso aleatorio en los puntos de código en una secuencia UTF-8 debido a su naturaleza de longitud variable. Si desea acceso aleatorio, debe usar una codificación de longitud fija, como UTF-32. Para eso puede usar el prefijo U en cadenas.

+2

Estaba usando el prefijo 'L' hasta el momento. Intenté reemplazarlo por 'u8' pero recibí el error' error C2065: 'u8': identificador no declarado'. – Qman

+1

@ user1563613 Es posible que su compilador aún no admita 'u8'. ¿Es Visual Studio? Si es así, probablemente debas usar UTF-16, que es lo que usan las API de Windows. –

+0

Es Visual Studio 2010. Si utilizo UTF-16 tengo que especificar la endianess, ¿correcto? Si es así, ¿no sería un problema al portar este programa a otras plataformas? – Qman

1

La razón por la que recibe la advertencia sobre \uFFFD es que usted está tratando de encajar FF FD dentro de un solo byte, ya que, como se anotó, UTF-8 obras en char s y es de longitud variable.

Si usa at o substr, posiblemente obtendrá respuestas incorrectas ya que estos métodos cuentan que un byte debe tener un carácter. Este no es el caso con UTF-8. En particular, con at, puede terminar con un solo byte de una secuencia de caracteres; con substr, podría romper una secuencia y terminar con una cadena UTF-8 inválida (comenzaría o terminaría con , \uFFFD, la misma que aparentemente está tratando de usar, y se perdería el carácter roto).

Yo recomendaría que use wchar para almacenar cadenas Unicode. Como el tipo es de al menos 16 bits, muchos más caracteres pueden caber en una sola "unidad".

+0

La peor parte es que no terminaría con un personaje de reemplazo. Romper una secuencia de bytes UTF-8 en el lugar incorrecto con substr simplemente da como resultado una secuencia inválida. Para obtener caracteres de reemplazo, debe validarlos y reemplazarlos manualmente. –

+0

@ R.MartinhoFernandes, de hecho. Sin embargo, creo que para cuando los datos se presenten al usuario, alguna capa de la pila habrá hecho el trabajo. (Aún así, como ha notado, permanecerá sin corregir en el programa C++). – zneak

+0

Entonces, ¿cómo haría para obtener correctamente las subcadenas o iterar sobre los caracteres? – Qman

9

Sí, la codificación UTF-8 se puede usar con char, string y stringstream. Un char contendrá una sola unidad de código UTF-8, de la cual se pueden requerir hasta cuatro para representar un único punto de código Unicode.

Sin embargo, existen algunos problemas al usar UTF-8 específicamente con los compiladores de Microsoft. Las implementaciones de C++ usan un 'conjunto de caracteres de ejecución' para varias cosas, como caracteres de codificación y literales de cadenas. VC++ siempre utiliza la codificación de la configuración regional del sistema como conjunto de caracteres de ejecución, y Windows no admite UTF-8 como la codificación de la configuración regional del sistema, por lo tanto, UTF-8 nunca puede hacerlo con el juego de caracteres de ejecución.

Esto significa que VC++ nunca produce intencionalmente literales de caracteres y cadenas UTF-8. En cambio, el compilador debe ser engañado.

El compilador convertirá desde la codificación de código fuente conocida a la codificación de ejecución. Esto significa que si el compilador utiliza la codificación de configuración regional tanto para la fuente como para las codificaciones de ejecución, entonces no se realiza ninguna conversión.Si puede obtener datos UTF-8 en el código fuente, pero hacer que el compilador piense que la fuente utiliza la codificación regional, los literales de caracteres y cadenas usarán la codificación UTF-8. VC++ utiliza la llamada 'BOM' para detectar la codificación fuente y utiliza la codificación de la configuración regional si no se detecta una lista de materiales. Por lo tanto, puede obtener literales de cadena codificados en UTF-8 guardando todos sus archivos fuente como "UTF-8 sin firma".

Existen advertencias con este método. Primero, no puede usar UCN con caracteres angostos y literales de cadena. Los nombres de carácter universales deben convertirse al juego de caracteres de ejecución, que no es UTF-8. Debe escribir el carácter literalmente para que aparezca como UTF-8 en el código fuente, o puede usar escapes hexadecimales donde escribe manualmente una codificación UTF-8. En segundo lugar, para producir caracteres anchos y literales de cadena, el compilador realiza una conversión similar desde la codificación de origen al conjunto de caracteres de ejecución amplia (que siempre es UTF-16 en VC++). Dado que estamos mintiendo al compilador sobre la codificación, se realizará esta conversión a UTF-16 incorrectamente. Por lo tanto, en literales de caracteres anchos y cadenas no se pueden usar literalmente caracteres que no sean ASCII, y en su lugar se deben usar UCN o escapes hexadecimales.


UTF-8 es de longitud variable (como es UTF-16). Los índices utilizados con at() y substr() son unidades de código en lugar de índices de puntos de caracteres o códigos. Entonces, si quiere una unidad de código particular, entonces puede simplemente indexar en la cadena o matriz o lo que sea normal. Si necesita un punto de código particular, entonces necesita una biblioteca que pueda comprender la composición de unidades de código UTF-8 en puntos de código (como Boost Unicode iterators library), o necesita convertir los datos UTF-8 en UTF-32. Si necesita caracteres percibidos por el usuario real, entonces necesita una biblioteca que comprenda cómo se componen los puntos de código en los caracteres. Imagino que ICU tiene esa funcionalidad, o podría implementar el Default Grapheme Cluster Boundary Specification del estándar Unicode.


La consideración anterior de UTF-8 sólo realmente importa para la forma de escribir los datos Unicode en el código fuente. Tiene poca relación con la entrada y salida del programa.

Si sus requisitos le permiten elegir cómo hacer las entradas y salidas, aún así recomiendo usar UTF-8 para la entrada. Dependiendo de lo que necesite hacer con la entrada, puede convertirla a otra codificación que sea fácil de procesar, o puede escribir sus rutinas de procesamiento para trabajar directamente en UTF-8.

Si quiere exportar algo a través de la consola de Windows, querrá un módulo bien definido para la salida que pueda tener diferentes implementaciones, porque la salida internacionalizada a la consola de Windows requerirá una implementación diferente de la salida a un archivo en Windows o consola y salida de archivos en otras plataformas. (En otras plataformas, la consola es solo otro archivo, pero la consola de Windows necesita un tratamiento especial.)