2011-02-14 9 views
5

Actualmente estoy cuidando de una aplicación que utiliza std::string y char para operaciones de cadenas - que está muy bien en Linux , ya que Linux es agnóstico a Unicode (o eso parece, realmente no lo sé, así que por favor corrígeme si estoy contando historias aquí). Este estilo actual conduce naturalmente a este tipo de declaraciones de función/clase:Unicode Portabilidad

std::string doSomethingFunkyWith(const std::string& thisdata) 
{ 
    /* .... */ 
} 

Sin embargo, si thisdata contiene caracteres Unicode, se mostrará erróneamente en las ventanas, ya que std::string no puede contener caracteres Unicode en Windows.

Así que se me ocurrió este concepto:

namespace MyApplication { 
#ifdef UNICODE 
    typedef std::wstring string_type; 
    typedef wchar_t  char_type; 
#else 
    typedef std::string string_type; 
    typedef char   char_type; 
#endif 

    /* ... */ 
    string_type doSomethingFunkyWith(const string_type& thisdata) 
    { 
     /* ... */ 
    } 
} 

¿Es una buena idea para ir con Unicode para apoyar en las ventanas?

Mi actual cadena de herramientas consiste en gcc/clang en Linux, y wine + MinGW para soporte de Windows (el test cruzado también se realiza a través de wine), si eso es importante.

+1

Creo que es razonable. Creo que este es el enfoque adoptado por muchas bibliotecas, como wxWidgets. – HighCommander4

+0

Sí, esto se hace con muchas bibliotecas, Windows para uno, como usted mencionó. – Marlon

+5

Más exactamente, la mayoría de los programas de Linux manejan Unicode como UTF-8, que es compatible con 'std :: string'. Pero eso significa que 'size()' y 'length()' darán el número de bytes, pero no necesariamente el número de puntos de código o glifos. Dependiendo de lo que esté haciendo con las cuerdas, es posible que no necesite más información. – aschepler

Respuesta

4

Los problemas de multiplataforma provienen del hecho de que hay muchas codificaciones, y una selección de codificación incorrecta conducirá a encuadernación de objetos. Una vez que aborde ese problema, debe poder usar std::wstring en todo su programa.

El flujo de trabajo habitual es:

raw_input_data = read_raw_data() 
input_encoding = "???" // What is your file or terminal encoding? 

unicode_data = convert_to_unicode(raw_input_data, input_encoding) 

// Do something with the unicode_data, store in some var, etc. 

output_encoding = "???" // Is your terminal output encoding the same as your input? 
raw_output_data = convert_from_unicode(unicode_data, output_encoding) 

print_raw_data(raw_data) 

cuestiones más Unicode proviene de detectar erróneamente los valores de input_encoding y output_encoding. En una distribución moderna de Linux esto generalmente es UTF-8. En Windows YMMV.

Estándar C++ no sé acerca de las codificaciones, debe utilizar alguna biblioteca como ICU para hacer la conversión.

+1

El uso de estas funciones 'convert' me parece lógico; También decidí usar las funciones para cambiar entre 'std :: wstring' y' std :: string' en lugares donde tiene sentido, en lugar de actualizar completamente la aplicación con 'string_type' ... lo que habría llevado bastante tiempo, y mucho menos abordar los literales de cadena (y prefijarlos con una 'L') –

5

Cómo usted almacena una cadena dentro de su aplicación es totalmente de usted, después de todo, nadie sabría mientras las cadenas permanezcan dentro de su aplicación. El problema comienza cuando intentas leer o escribir cadenas del mundo exterior (consola, archivos, tomas de corriente, etc.) y aquí es donde importa el sistema operativo.

Linux no es exactamente "agnóstico" para Unicode: reconoce Unicode pero las funciones de biblioteca estándar asumen la codificación UTF-8, por lo que las cadenas Unicode encajan en las matrices estándar char. Windows, por otro lado, usa codificación UTF-16, por lo que necesita una matriz wchar_t para representar caracteres de 16 bits.

El typedef que usted propuso debería funcionar bien, pero tenga en cuenta que esto solo no hace que su código sea portátil. Como ejemplo, si desea almacenar texto en archivos de manera portátil, debe elegir una codificación y adherirse a ella en todas las plataformas; esto podría requerir la conversión entre codificaciones en ciertas plataformas.

3

Linux admite Unicode, simplemente usa UTF-8. Probablemente una mejor forma de hacer que su sistema sea portátil sería utilizar International Components for Unicode y tratar todos los objetos std::string como si contuvieran caracteres UTF-8, y convertirlos a UTF-16 según sea necesario al invocar las funciones de Windows. Casi siempre tiene sentido usar UTF-8 sobre UTF-16, ya que UTF-8 usa menos espacio para algunos de los caracteres más utilizados (por ejemplo, inglés *) y más espacio para caracteres menos frecuentes, mientras que UTF-16 desperdicia espacio por igual para todos los personajes, sin importar con qué frecuencia se usan.

Si bien puede usar su typedefs, esto significa que debe escribir dos copias de cada función que tenga que ver con las cadenas. Creo que sería más eficiente simplemente hacer todos los cálculos internos en UTF-8 y simplemente traducir eso a/desde UTF-16 si es necesario al ingresar/dar salida según sea necesario.

* Para HTML, XML, JSON y que utilizan Inglés como parte de la codificación (por ejemplo, "<html>, <cuerpo>, etc.), independientemente del idioma de los valores, esto todavía puede ser una victoria para extranjeros

1

El problema para Linux y el uso de Unicode es que todas las funciones de IO y de la mayoría del sistema usan UTF-8 y el tipo de caracteres anchos es de 32 bits. Luego hay interfaces con Java y otros programas que requieren UTF-16.

Como sugerencia para la compatibilidad con Unicode, consulte la biblioteca de OpenRTL en http://code.google.com/p/openrtl que admite todos los UTF-8, UTF-16 y UT F-32 en Windows, Linux, Osx y Ios. El soporte de Unicode no es solo los tipos de caracteres, sino también la intercalación Unicode, la normalización, el plegado de mayúsculas y minúsculas, el título y aproximadamente 64 propiedades diferentes de caracteres Unicode por cada carácter de 32 bits sin signo.

El código OpenRTL está ahora listo para admitir char8_t, char16_t y char32_t para los nuevos estándares C++, aunque los mismos tipos de caracteres son compatibles con macros para compiladores C y C++ existentes. Creo que para Unicode y para el procesamiento de cadenas puede ser lo que quieras para tu biblioteca.

El punto es que si usa OpenRTL, puede construir el sistema usando el tipo OpenRTL "char_t". Esto respalda la noción de que toda su biblioteca puede construirse en modo UTF8, UTF16 o UTF32, incluso en Linux, porque OpenRTL ya está manejando todas las interfaces con muchas funciones del sistema, como archivos y cosas. Tiene sus propias funciones print_f, por ejemplo.

De forma predeterminada, el carácter char_t se asigna al tipo de caracteres anchos. Entonces en Windows es de 32 bits y en Linux es de 32 bits. Pero también puedes hacer que sea de 8 bits en todas partes, por ejemplo. También tiene el soporte para hacer una rápida decodificación UTF dentro de bucles usando macros.

Así que en lugar de ifdeffing entre wchar_t y char, puedes construir todo usando char_t y OpenRTL se ocupa del resto.

Cuestiones relacionadas