2010-01-10 7 views
17

Sé que ya hay varias preguntas sobre StackOverflow sobre std::string frente a std::wstring o similar, pero ninguna de ellas propuso una solución completa.¿Cuál es la forma óptima multiplataforma de manejar cadenas Unicode bajo C++?

Con el fin de obtener una buena respuesta que debería definir los requisitos:

  • multiplataforma uso, debe funcionar en Windows, OS X y Linux
  • mínimo esfuerzo para conversión a/desde la plataforma específica Cadenas de Unicode como CFStringRef, wchar_t *, char* como UTF-8 u otros tipos según lo requiera OS API. Observación: No necesito compatibilidad con la conversión de páginas de códigos porque espero usar solo funciones compatibles con Unicode en todos los sistemas operativos compatibles.
  • si requiere una biblioteca externa, esta debería ser de código abierto y bajo una licencia muy liberal como BSD pero no LGPL.
  • ser capaz de utilizar un printf format sintaxis o similar.
  • manera fácil de asignar/desasignar cadenas
  • el rendimiento no es muy importante porque supongo que las cadenas Unicode se usan solo para la interfaz de usuario de la aplicación.
  • algún ejemplo podría sería apreciada

apreciaría realmente sólo una solución propuesta por la respuesta, al hacer esto la gente puede votar por su alternativa preferida. Si tiene más de una alternativa, simplemente agregue otra respuesta.

Por favor, indique algo que funcionó bien para usted.

preguntas relacionadas:

+2

¿Qué quiere decir por "tratar con cadenas Unicode"? ¿Simplemente quieres algo que pueda almacenar secuencias de puntos de código Unicode? ¿Algo que maneja correctamente la intercalación específica de la cultura? ¿Algo que sea capaz de manejar formas canónicas y no canónicas de una cuerda? – jalf

+0

@jalf ¡Buen punto! Olvidé mencionar que excluí deliberadamente el uso avanzado de cadenas como la modificación de cadenas o los formularios de normalización, clasificación. Supuse que, por simplicidad, solo usaría estas cadenas para mostrar (pero podría necesitar usar formato de impresión o concatenaciones de cadenas, pero no más). Cualquier cosa más que esto requeriría ICU u otras librerías. – sorin

Respuesta

5

Igual respuesta Adam Rosenfield (1), pero yo uso UTFCPP su lugar.

+0

+1, biblioteca interesante, muy idiomática. – avakar

+0

Que funciona igual de bien con std :: wstring para representación interna. Elige tu opción. –

7

recomendaría encarecidamente el uso de UTF-8 internamente en su aplicación, utilizando edad char* o std::string para los datos de almacenamiento normal . Para interactuar con las API que usan una codificación diferente (ASCII, UTF-16, etc.), recomendaría usar libiconv, que está licenciado bajo la LGPL.

Ejemplo de uso:

class TempWstring 
{ 
public: 
    TempWstring(const char *str) 
    { 
    assert(sUTF8toUTF16 != (iconv_t)-1); 
    size_t inBytesLeft = strlen(str); 
    size_t outBytesLeft = 2 * (inBytesLeft + 1); // worst case 
    mStr = new char[outBytesLeft]; 
    char *outBuf = mStr; 
    int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft); 
    assert(result == 0 && inBytesLeft == 0); 
    } 

    ~TempWstring() 
    { 
    delete [] mStr; 
    } 

    const wchar_t *Str() const { return (wchar_t *)mStr; } 

    static void Init() 
    { 
    sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8"); 
    assert(sUTF8toUTF16 != (iconv_t)-1); 
    } 

    static void Shutdown() 
    { 
    int err = iconv_close(sUTF8toUTF16); 
    assert(err == 0); 
    } 

private: 
    char *mStr; 

    static iconv_t sUTF8toUTF16; 
}; 

iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1; 

// At program startup: 
TempWstring::Init(); 

// At program termination: 
TempWstring::Shutdown(); 

// Now, to convert a UTF-8 string to a UTF-16 string, just do this: 
TempWstring x("Entr\xc3\xa9""e"); // "Entrée" 
const wchar_t *ws = x.Str(); // valid until x goes out of scope 

// A less contrived example: 
HWND hwnd = CreateWindowW(L"class name", 
          TempWstring("UTF-8 window title").Str(), 
          dwStyle, x, y, width, height, parent, menu, hInstance, lpParam); 
+4

+1, no puedo estar más de acuerdo con utf-8 y 'std :: string'. – avakar

+2

Entonces * ¿cada * operación de cadena trivial requiere una conversión? –

+2

Su recomendación es la forma EXACTA opuesta de todo el sistema operativo. Internamente Win/Mac usa UTF-16 (porque es de tamaño fijo (no realmente, pero para la mayoría de los propósitos prácticos) (realmente es UCS-2 pero no se lo dice a nadie)). Mientras el almacenamiento se realiza en UTF-8. –

2

Hace poco estuve en un proyecto que decidió usar std :: wstring para un proyecto multiplataforma porque "las cadenas anchas son Unicode, ¿verdad?" Esto dio lugar a una serie de dolores de cabeza:

  • ¿Qué tan grande es el valor escalar en un wstring?Respuesta: depende de la implementación del compilador. En Visual Studio (Win), es de 16 bits. Pero en Xcode (Mac), es de 32 bits.
  • Esto condujo a la desafortunada decisión de usar UTF-16 para la comunicación a través del cable. Pero, ¿qué UTF-16? Hay dos: UTF-16BE (big-endian) y UTF16-LE (little-endian). No ser claro en esto llevó a aún más errores.

Cuando está en un código específico de plataforma, tiene sentido utilizar la representación nativa de la plataforma para comunicarse con sus API. Pero para cualquier código que se comparte entre plataformas, o se comunica entre plataformas, evite toda ambigüedad y use UTF-8.

+0

Qué UTF-16 venir por el cable es fácil Simplemente asegúrese de que la BOM se envíe como el primer carácter. La capa receptora (la que se encuentra arriba transporta luego reorganiza el mensaje según sea necesario. Pero estoy de acuerdo que UTF-8 para el transporte es más fácil y usualmente más compacto (y la transcodificación UTF-16 -> UTF-8 es trivial) –

+2

Me gusta el transporte El almacenamiento es más fácil si usa UTF-8. –

+1

Creo que * si * está usando UTF-16 por cable, debe adherirse a la endiacia de la red, esto es big-endian. No es necesario hacer ningún protocolo más complejo – sorin

1

Regla general: utilice la plataforma nativa Unicode para el procesamiento (UTF-16 o UTF-32) y UTF-8 para el intercambio de datos (comunicación, almacenamiento).

Si todas las API nativas usan UTF-16 (por ejemplo en Windows), tener sus cadenas como UTF-8 significa que tendrá que convertir todas las entradas a UTF-16, llamar a Win API, luego convertir la respuesta a UTF-8. Muy doloroso

Pero si el problema principal es la interfaz de usuario, las cadenas son el problema simple. El más difícil es el marco de la interfaz de usuario. Y para eso recomendaría wxWidgets (http://www.wxWidgets.org). Admite muchas plataformas, maduro (17 años y aún muy activo), widgets nativos, Unicode, licencia liberal.

1

Iría para la representación UTF16 en memoria y UTF-8 o 16 en disco duro o cable. La razón principal: UTF16 tiene un tamaño fijo para cada "letra". Esto simplifica muchos deberes al trabajar con la cuerda (serrar, reemplazar partes, ...).

La única razón para UTF-8 es la reducción del uso de memoria para letras "occidental/latina". Puede usar esta representación para almacenamiento de disco o transporte a través de la red. También tiene la ventaja de que no necesita preocuparse por el orden de bytes al cargar/guardar en disco/cable.

Teniendo esto en cuenta, iría por std :: wstring internamente o, si la biblioteca de su GUI ofrece una Widestring, utilícela (como QString de QT). Y para el almacenamiento de disco, escribiría un contenedor independiente de plataforma pequeña para la API de la plataforma. O echaría un vistazo a unicode.org si tienen el código dependiente de plataformas disponible para esta conversión.


para aclaración: las letras coreanas/japonesas NO son occidentales/latinas. Los japoneses son por ejemplo kanji. Es por eso que mencioné el conjunto de caracteres latinos.


para UTF-16 no es 1 caracter/2 bytes. Esta suposición solo es cierta para los caracteres que se encuentran en el plano multilingüe básico (consulte: http://en.wikipedia.org/wiki/UTF16). Todavía la mayoría de los usuarios de UTF-16 asumen que todos los caracteres están en BMP. Si no se puede garantizar esto para su aplicación, puede cambiar a UTF32 o cambiar a UTF8.

Aún UTF-16 se usa por las razones mencionadas anteriormente en una gran cantidad de API (por ejemplo, de Windows, QT, Java, .NET, wxWidgets)

+4

UTF16 no tiene un tamaño fijo para cada letra. –

+2

UTF-8 tiene otros beneficios, como poder para ser procesado por las funciones estándar de cadena C. –

+0

Un propos "uso reducido de memoria para letras occidentales/latinas": las cosas son más complicadas de lo que parecen Wikipedia dice: "Por ejemplo, tanto el artículo japonés como el coreano UTF-8 sobre W ikipedia toma más espacio si se guarda como UTF-16 que la versión original UTF-8 ". –

Cuestiones relacionadas