2009-01-12 15 views
9

Al mirar unicode standard, se recomienda utilizar el char s plano para almacenar cadenas codificadas en UTF-8. ¿Funciona esto como se esperaba con C++ y el std::string básico, o existen casos en los que la codificación UTF-8 puede crear problemas?¿Cuál es la mejor manera de almacenar cadenas UTF-8 en memoria en C/C++?

Por ejemplo, al calcular la longitud, puede que no sea idéntica a la cantidad de bytes: ¿cómo se supone que se manejará esto? Leyendo el estándar, probablemente estoy bien usando una matriz de char para el almacenamiento, pero aún necesitaré escribir funciones como strlen etc., que funcionan en el texto codificado, por lo que entiendo el problema, el estándar las rutinas son solo ASCII o esperan literales anchos (16 bits o más), que no son recomendados por el estándar Unicode. Hasta el momento, la mejor fuente que encontré sobre la materia de codificación es un post en Joel's on Software, pero no explica lo que pobres desarrollador de C++ deberíamos usar :)

Respuesta

5

Hay una biblioteca llamada "UTF8-CPP", que le permite almacenar sus cadenas UTF-8 en objetos estándar std :: string y proporciona funciones adicionales para enumerar y manipular caracteres utf-8.

No lo he probado todavía, así que no sé lo que vale, pero estoy considerando usarlo yo mismo.

+0

Este es probablemente el camino a seguir. También hay una biblioteca de ICU, que hace más o menos lo mismo. – sastanin

0

De UTF-8 and Unicode FAQ: C support for Unicode:

#include <stdio.h> 
#include <locale.h> 

int main() 
{ 
    if (!setlocale(LC_CTYPE, "")) { 
    fprintf(stderr, "Can't set the specified locale! " 
      "Check LANG, LC_CTYPE, LC_ALL.\n"); 
    return 1; 
    } 
    printf("%ls\n", L"Schöne Grüße"); 
    return 0; 
} 

También desde here:

la buena noticia es que si se utiliza wchar_t* cuerdas y la familia de funciones relacionadas con ellos, como wprintf, wcslen y wcslcat, usted es que se ocupa de los valores Unicode. En el mundo C++, puede usar std::wstring a para proporcionar una interfaz amigable. Mi único reclamo es que estos son caracteres de 32 bits (4 byte), por lo que son ceros de memoria para todos los idiomas. La razón para esta opción es que garantiza que cada carácter posible se puede representar en un valor.

PS. Esto es probablemente específico de Linux. Hay una biblioteca de ICU para manejar cosas complicadas.

+0

Esto no funciona bien cuando lo intento en OS X con GCC 4.01: Imprime los caracteres no ASCII como caracteres escapados en código octal. Cuando escribo printf ("% s \ n", "Schöne Grüße"); en su lugar, se imprime correctamente. Por lo tanto, esto no es una solución para obtener el número de caracteres utf-8 en una cadena. –

+0

No puedo decir si para OS X, pero este ejemplo definitivamente funciona con GCC 4.3.2 en GNU/Linux, * en una configuración regional UTF-8 *. ¿Cuál es tu ubicación en OS X? Sospecho que no es una configuración regional Unicode. Además, probablemente, las configuraciones regionales se manejan de forma diferente en OS X, no lo sé. – sastanin

+1

Wrong en muchos niveles, me temo. Chars fuera del juego de caracteres garantizado; asumiendo que la consola puede imprimir wchar_t's. wchar_t tiene 2 bytes en la mayoría de las PC, – MSalters

1

Lo que nos decidimos por: almacenar UTF8 en std :: string. Ahora puede hacer la mayoría de las operaciones, excepto por cosas como calcular la longitud. Utilice una función de conversión UTF8-> std :: wstring (boost :: from_utf8, por ejemplo) para convertir a std :: wstring cuando necesite tales operaciones.

2

Depende de lo que quiera hacer con la secuencia UTF8. Si todo lo que le interesa es leer dentro y fuera de las cadenas UTF8, todo funciona siempre que haya establecido la configuración regional correcta. Hemos hecho esto por un tiempo. Tenemos varios procesos de servidor que no hacen nada con cadenas como tal. El usuario establece las cadenas en Java y llega como UTF8 y las gestionamos en los búfers estándar de c str. A continuación, enviamos los datos a Java que los convierte de nuevo.

Si desea la longitud en caracteres UTF8, quiere funciones que puedan manejar la traducción por usted.

Pero se puede liar por ejemplo utf8-strlen

2

strlen cuenta el número de caracteres que no son nulos antes de la primera \ 0. En UTF-8, ese recuento es un número razonable (número de bytes utilizados), pero el recuento no es el número de caracteres (un carácter UTF-8 es típicamente 1-4 caracteres). basic_string no almacena \ 0, pero también mantiene un recuento de bytes.

strcpy o el copiador de la cadena básica copia todos los bytes sin mirar demasiado de cerca.

Encontrar una subcadena funciona bien, debido a la forma en que se codifica UTF_8. Los valores permitidos para el primer byte de un personaje son distintos del segundo al cuarto byte (el anterior nunca comienza con 10xxxxxx, el último siempre)

Tomar una subcadena es complicado: ¿cómo se especifica la posición? Si el principio y el final se encontraron al buscar marcadores de texto ASCII (por ejemplo, [y]), no hay problema. Acabas de obtener los bytes en el medio, que también son una cadena UTF8 válida. Sin embargo, no puede codificar posiciones, ni siquiera compensaciones relativas. Incluso un desplazamiento relativo de +1 carácter puede ser difícil; ¿Cuántos bytes es eso? Terminará escribiendo una función como SkipOneChar.

3

Un ejemplo con ICU library (C, C++, Java):

#include <iostream> 
#include <unicode/unistr.h> // using ICU library 

int main(int argc, char *argv[]) { 
    // constructing a Unicode string 
    UnicodeString ustr1("Привет"); // using platform's default codepage 
    // calculating the length in characters, should be 6 
    int ulen1=ustr1.length(); 
    // extracting encoded characters from a string 
    int const bufsize=25; 
    char encoded[bufsize]; 
    ustr1.extract(0,ulen1,encoded,bufsize,"UTF-8"); // forced UTF-8 encoding 
    // printing the result 
    std::cout << "Length of " << encoded << " is " << ulen1 << "\n"; 
    return 0; 
} 

edificio como

$ g++ -licuuc -o icu-example{,.cc} 

corriendo

$ ./icu-example 
Length of Привет is 6 

Obras para mí en Linux con GCC 4.3.2 y libicu 3.8.1. Tenga en cuenta que se imprime en UTF-8 independientemente de la configuración regional del sistema. No lo verás correctamente si el tuyo no es UTF-8.

Cuestiones relacionadas