2010-10-16 35 views
10

He leído algunas publicaciones sobre las mejores prácticas para cadenas y codificación de caracteres en C++, pero estoy luchando un poco para encontrar un enfoque de propósito general que me parezca razonablemente simple y correcto. ¿Podría solicitar comentarios sobre lo siguiente? Estoy inclinado a usar UTF-8 y UTF-32, y para definir algo como:Cadenas y codificación de caracteres en C++

typedef std::string string8; 
typedef std::basic_string<uint32_t> string32; 

La clase String8 se utilizaría para UTF-8, y que tiene un tipo separado es sólo un recordatorio de la codificación . Una alternativa sería que string8 fuera una subclase de std :: string y eliminar los métodos que no son del todo correctos para UTF-8.

La clase string32 se usaría para UTF-32 cuando se desea un tamaño de caracteres fijo.

Las funciones UTF-8 CPP, utf8 :: utf8to32() y utf8 :: utf32to8(), o funciones de contenedor más simples, se usarían para convertir entre las dos.

+0

Tenga en cuenta que 'string8' sigue siendo del mismo tipo que' std :: string'; solo tiene un nombre diferente. –

+0

¿Qué funciones de 'std :: basic_string' * son * correctas para UTF-8? – dalle

+0

¿Qué le compra UTF-32 a través de wstring/Unicode? Por cierto, Visual Studio define 'u16string' y' u32string'. –

Respuesta

9

Si planea pasar cuerdas y nunca inspeccionarlas, puede usar plain std::string aunque es un trabajo pobre.

El problema es que la mayoría de los marcos, incluso el estándar, tienen estúpidamente (creo) la codificación forzada en la memoria. Digo estúpido porque la codificación solo debería importar en la interfaz, y esas codificaciones no están adaptadas para la manipulación de los datos en la memoria.

Además, la codificación es fácil (es una simple transposición CodePoint -> bytes e inversamente) mientras que la dificultad principal es en realidad sobre la manipulación de los datos.

Con un 8 bits o 16 bits corres el riesgo de cortar un personaje en el medio porque ni std::string ni std::wstring saben qué es un carácter Unicode. Peor aún, incluso con una codificación de 32 bits, existe el riesgo de separar un carácter de los signos diacríticos que se le aplican, lo cual también es estúpido.

El soporte de Unicode en C++ es, por lo tanto, extremadamente insatisfactorio en lo que respecta al estándar.

Si realmente desea manipular la cadena Unicode, necesita un contenedor con reconocimiento Unicode. La forma habitual es usar la biblioteca , aunque su interfaz es realmente C-ish. Sin embargo, obtendrá todo lo que necesita para trabajar en Unicode con múltiples idiomas.

+1

Encontré un poco de miedo tu comentario sobre diacríticos. En cierto sentido, es más relevante para lo que estoy tratando de hacer, que es manejar cadenas "correctamente" de una manera relativamente simple. – nassar

+0

@nassar: desafortunadamente da miedo porque no tenemos el soporte adecuado: '( –

+0

ICU tiene (entre otras interfaces en C++) una clase de cadena C++ que interopera con std :: string –

1

El enfoque de rasgos descrito here puede ser útil. Es una técnica antigua pero útil.

1

No se especifica qué codificación de caracteres se debe usar para string, wstring, etc. La forma común es usar unicode en cadenas anchas. Qué tipos y codificaciones se deben usar depende de sus requisitos.

Si solo necesita pasar datos de A a B, elija std :: cadena con codificación UTF-8 (no introduzca un tipo nuevo, solo use std :: string). Si debe trabajar con cadenas (extraer, concat, ordenar, ...) elija std :: wstring y como codificación UCS2/UTF-16 (solo BMP) en Windows y UCS4/UTF-32 en Linux. El beneficio es el tamaño fijo: cada carácter tiene un tamaño de 2 (o 4 para UCS4) bytes, mientras que std :: string con UTF-8 devuelve resultados de longitud incorrecta().

Para la conversión, puede marcar sizeof (std :: wstring :: value_type) == 2 o 4 para elegir UCS2 o UCS4. Estoy usando la biblioteca de ICU, pero puede haber libs de contenedor simple.

No se recomienda derivar de std :: string porque basic_string no está diseñado (carece de miembros virtuales, etc.). Si realmente realmente necesita su propio tipo como std :: basic_string < my_char_type> escriba una especialización personalizada para esto.

El nuevo estándar C++ 0x define wstring_convert <> y wbuffer_convert <> de convertir con un std :: codecvt de un juego de caracteres estrecha a una amplia charset (por ejemplo UTF-8 a UCS2). Visual Studio 2010 ya ha implementado esto, afaik.

+2

He evitado intencionalmente UCS-2, porque me parece que si uno se toma la molestia de manejar la codificación de caracteres, uno también podría hacerlo bien y soportar Unicode completo. (Al mismo tiempo, estoy buscando algo menos engorroso que la UCI para uso general). En cuanto a UTF-16, parece tener las desventajas de la codificación de longitud variable y el uso de mucha memoria. Es por eso que propongo usar UTF-8 y UTF-32 en combinación. – nassar

+0

Punto tomado sobre derivar de std :: string. ¡Gracias! – nassar

+1

Creo que definir un nuevo tipo no es en absoluto esencial, pero mucha gente que ve std :: string en el código tenderá a olvidarse de los caracteres de varios bytes y utilizará incorrectamente las posiciones de los caracteres. El hecho de que sea UTF-8 se puede transmitir en los comentarios, pero tener un recordatorio en el nombre del tipo parece útil porque los métodos como std :: string :: insert() sugieren caracteres de 8 bits en mi opinión. – nassar

Cuestiones relacionadas