verificar revista lecturas horas home gubernamental etica ethos certificacion cdpe acceso c++ unicode character-encoding

c++ - revista - ¿Qué puede representar exactamente wchar_t?



revista ethos (5)

Entonces, si quiero tratar con caracteres Unicode, ¿debo usar wchar_t ?

En primer lugar, tenga en cuenta que la codificación no le obliga a utilizar ningún tipo en particular para representar un determinado carácter. Puede usar char para representar caracteres Unicode como wchar_t can - solo tiene que recordar que hasta 4 char juntos formarán un punto de código válido dependiendo de la codificación UTF-8, UTF-16 o UTF-32, mientras que wchar_t puede use 1 (UTF-32 en Linux, etc.) o hasta 2 trabajando juntos (UTF-16 en Windows).

A continuación, no hay una codificación definida de Unicode. Algunas codificaciones de Unicode usan un ancho fijo para representar puntos de código (como UTF-32), otras (como UTF-8 y UTF-16) tienen longitudes variables (la letra ''a'' por ejemplo seguramente usará hasta 1 byte, pero aparte del alfabeto inglés, otros caracteres seguramente usarán más bytes para la representación).

Por lo tanto, debe decidir qué tipo de caracteres desea representar y luego elegir la codificación correspondiente. Dependiendo del tipo de caracteres que desee representar, esto afectará la cantidad de bytes que tomarán sus datos. Por ejemplo, el uso de UTF-32 para representar caracteres en su mayoría en inglés dará lugar a muchos 0 bytes. UTF-8 es una mejor opción para muchos idiomas basados ​​en el latín, mientras que UTF-16 es generalmente una mejor opción para los idiomas de Asia oriental.

Una vez que haya decidido sobre esto, debe minimizar la cantidad de conversiones y mantenerse coherente con su decisión.

En el siguiente paso, puede decidir qué tipo de datos es el adecuado para representar los datos (o qué tipo de conversiones puede necesitar).

Si desea realizar una manipulación / interpretación de texto sobre una base de punto de código, el char no es el camino a seguir si tiene, por ejemplo, kanji japonés. Pero si solo quieres comunicar tus datos y no los consideres más como una secuencia cuantitativa de bytes, puedes ir con char .

El enlace a UTF-8 en todas partes ya se publicó como un comentario, y le sugiero que también eche un vistazo allí. Otra buena lectura es lo que todo programador debe saber sobre las codificaciones .

Como hasta ahora, solo hay compatibilidad de lenguaje rudimentario en C ++ para Unicode (como los tipos de datos char16_t y char32_t , y los prefijos literales u8 / u / U ). Así que elegir una biblioteca para codificar codificaciones (especialmente conversiones) ciertamente es un buen consejo.

Según el documento de wchar_t en wchar_t :

wchar_t - tipo para la representación de caracteres anchos (ver cadenas anchas). Se requiere que sea lo suficientemente grande como para representar cualquier punto de código de carácter admitido (32 bits en sistemas que admiten Unicode. Una excepción notable es Windows, donde wchar_t es de 16 bits y contiene unidades de código UTF-16) Tiene el mismo tamaño, firmeza y alineación como uno de los tipos enteros, pero es un tipo distinto.

El estándar dice en [basic.fundamental]/5 :

El tipo wchar_t es un tipo distinto cuyos valores pueden representar códigos distintos para todos los miembros del conjunto de caracteres extendido más grande especificado entre las configuraciones regionales compatibles. El tipo wchar_t tendrá los mismos requisitos de tamaño, firmeza y alineación que uno de los otros tipos integrales, llamado su tipo subyacente. Los tipos char16_t y char32_t denotan tipos distintos con el mismo tamaño, firmeza y alineación que uint_least16_t y uint_least32_t , respectivamente, en <cstdint> , denominados tipos subyacentes.

Entonces, si quiero tratar con caracteres Unicode, ¿debo usar wchar_t ?

De forma equivalente, ¿cómo puedo saber si un carácter Unicode específico es "compatible" con wchar_t ?


Entonces, si quiero tratar con caracteres Unicode, ¿debo usar wchar_t?

Eso depende de con qué codificación estés tratando. En el caso de UTF-8, estás bien con char y std :: string. UTF- 8 significa que la unidad de codificación mínima es de 8 bits: todos los puntos de código Unicode de U + 0000 a U + 007F están codificados por solo 1 byte. Comenzando con el punto de código U + 0080 UTF-8 usa 2 bytes para la codificación, a partir de U + 0800 usa 3 bytes y de U + 10000 4 bytes. Para manejar este ancho variable (1 byte - 2 byte - 3 byte - 4 byte), el char se ajusta mejor. Tenga en cuenta que las funciones C como strlen proporcionarán resultados basados ​​en bytes: "öö" de hecho es un texto de 2 caracteres, pero strlen devolverá 4 porque ''ö'' está codificado a 0xC3B6.

UTF- 16 significa que la unidad de codificación mínima es de 16 bits: todos los puntos de código de U + 0000 a U + FFFF están codificados por 2 bytes; a partir de U + 100000 se utilizan 4 bytes. En el caso de UTF-16, debe usar wchar_t y std :: wstring porque la mayoría de los caracteres que encontrará se codificarán en 2 bytes. Cuando se usa wchar_t, ya no se pueden usar funciones C como strlen; Tienes que usar los equivalentes de caracteres anchos como wcslen.

Al usar Visual Studio y compilar con la configuración "Unicode" obtendrá UTF-16: TCHAR y CString se basarán en wchar_t en lugar de char.


En primer lugar, debe verificar (como señala en su pregunta) si está usando Windows y Visual Studio C ++ con wchar_t siendo 16bits, porque en ese caso, para usar el soporte completo de Unicode, deberá asumir UTF-16 codificacion

El problema básico aquí no es el sizeof wchar_t que está utilizando, pero si las bibliotecas que va a usar son compatibles con el soporte completo de Unicode.

Java tiene un problema similar, ya que su tipo de caracteres es de 16 bits de ancho, por lo que a priori no podía soportar el espacio Unicode completo, pero lo hace , ya que utiliza la codificación UTF-16 y el par se sustituye para hacer frente a los puntos de código completos de 24 bits.

También vale la pena tener en cuenta que UNICODE utiliza solo el plano alto para codificar puntos de código raros, que normalmente no se usan a diario.

De todos modos, para la compatibilidad con Unicode, debe usar conjuntos de caracteres amplios, por lo que wchar_t es un buen comienzo. Si va a trabajar con Visual Studio, debe comprobar cómo se tratan las bibliotecas con los caracteres Unicode.

Otra cosa a tener en cuenta es que las bibliotecas estándar se ocupan de los juegos de caracteres (y esto incluye unicode) solo cuando se agrega soporte de configuración regional (esto requiere que se inicialice alguna biblioteca, por ejemplo, setlocale(3) ) y así, no verá unicode en absoluto. (solo ascii básico) en los casos en que no haya llamado setlocale(3) .

Existen amplias funciones de caracteres para casi cualquier función str*(3) , así como para cualquier función de biblioteca stdio.h , para tratar con wchar_t s. Una pequeña excavación en el archivo /usr/include/wchar.h revelará los nombres de las rutinas. Vaya a las páginas del manual para obtener documentación sobre ellos: fgetws(3) , fputwc(3) , fputws(3) , fwide(3) , fwprintf(3) , ...

Finalmente, considere nuevamente que, si está tratando con Microsoft Visual C ++, tiene una implementación diferente desde el principio. Incluso si logran ser completamente compatibles con el estándar , tendrá que hacer frente a algunas idiosincrasias de tener una implementación diferente. Probablemente tendrás diferentes nombres de funciones para algunos usos.


Todo depende de lo que quieras decir con "lidiar con", pero una cosa es segura: en lo que respecta a Unicode, std::basic_string no proporciona ninguna funcionalidad real.

En cualquier programa en particular, deberá realizar un número X de operaciones compatibles con Unicode, por ejemplo, coincidencia inteligente de cadenas, plegado de casos, expresiones regulares, ubicación de saltos de palabras, usar una cadena Unicode como un nombre de ruta tal vez, y así sucesivamente.

Apoyando estas operaciones casi siempre habrá algún tipo de biblioteca y / o API nativa provista por la plataforma, y ​​el objetivo para mí sería almacenar y manipular mis cadenas de tal manera que estas operaciones puedan llevarse a cabo sin el conocimiento disperso de La biblioteca subyacente y la API nativa son compatibles con todo el código más de lo necesario. También quisiera asegurarme del futuro en cuanto al ancho de los caracteres que almaceno en mis cuerdas en caso de que cambie de opinión.

Supongamos, por ejemplo, que decide utilizar la ICU para hacer el trabajo pesado. Inmediatamente hay un problema obvio: un icu::UnicodeString no está relacionado de ninguna manera con std::basic_string . ¿Qué hacer? ¿Trabaja exclusivamente con icu::UnicodeString todo el código? Probablemente no.

O tal vez el enfoque de la aplicación cambia de los idiomas europeos a los asiáticos, por lo que UTF-16 se convierte (quizás) en una mejor opción que UTF-8.

Entonces, mi elección sería utilizar una clase de cadena personalizada derivada de std::basic_string , algo como esto:

typedef wchar_t mychar_t; // say class MyString : public std::basic_string <mychar_t> { ... };

De inmediato, tiene flexibilidad para elegir el tamaño de las unidades de código almacenadas en su contenedor. Pero puedes hacer mucho más que eso. Por ejemplo, con la declaración anterior (y después de agregar la plantilla para los distintos constructores que debe proporcionar para reenviarlos a std::basic_string ), aún no puede decir:

MyString s = "abcde";

Debido a que "abcde" es una cadena estrecha y varios constructores para std::basic_string <wchar_t> todos esperan una cadena ancha. Microsoft resuelve esto con una macro ( TEXT ("...") o __T ("...") ), pero eso es un dolor. Todo lo que tenemos que hacer ahora es proporcionar un constructor adecuado en MyString , con la firma MyString (const char *s) , y el problema está resuelto.

En la práctica, este constructor probablemente esperaría una cadena UTF-8, independientemente del ancho de carácter subyacente utilizado para MyString , y la convertirá si es necesario. Alguien comenta aquí en algún lugar que debes almacenar tus cadenas como UTF-8 para que puedas construirlas a partir de literales UTF-8 en tu código. Bueno, ahora hemos roto esa restricción. El ancho del carácter subyacente de nuestras cadenas puede ser cualquier cosa que nos guste.

Otra cosa de la que la gente ha estado hablando en este hilo es que find_first_of puede no funcionar correctamente para las cadenas UTF-8 (y, de hecho, algunas de ellas también). Bueno, ahora puede proporcionar una implementación que haga el trabajo correctamente. Debería tomar alrededor de media hora. Si hay otras implementaciones ''rotas'' en std::basic_string (y estoy seguro de que las hay), entonces la mayoría de ellas probablemente se puedan reemplazar con una facilidad similar.

En cuanto al resto, depende principalmente del nivel de abstracción que desee implementar en su clase MyString. Si su aplicación está contenta de tener una dependencia en la ICU, por ejemplo, puede proporcionar un par de métodos para convertir desde y hacia un icu::UnicodeString . Eso es probablemente lo que la mayoría de la gente haría.

O si necesita pasar cadenas UTF-16 a / desde las API nativas de Windows, puede agregar métodos para convertir const WCHAR * desde const WCHAR * (que de nuevo se implementaría de tal manera que funcionen para todos los valores de mychar_t). O puede ir más lejos y abstraer parte o todo el soporte de Unicode proporcionado por la plataforma y la biblioteca que está utilizando. La Mac, por ejemplo, tiene una rica compatibilidad con Unicode, pero solo está disponible en Objective-C, por lo que tiene que envolverla. Depende de cuán portátil quieras que sea tu código.

Por lo tanto, puede agregar la funcionalidad que desee, probablemente de manera continua a medida que avanza el trabajo, sin perder la capacidad de llevar sus cadenas como std::basic_string . De un tipo u otro. Solo intente no escribir código que asuma que sabe cuán ancho es, o que no contiene pares sustitutos .


wchar_t se usa en Windows que usa el formato UTF16-LE. wchar_t requiere amplias funciones de caracteres. Por ejemplo, wcslen(const wchar_t*) lugar de strlen(const char*) y std::wstring lugar de std::string

Las máquinas basadas en Unix (Linux, Mac, etc.) utilizan UTF8. Esto usa char para almacenamiento, y las mismas funciones C y C ++ para ASCII, como strlen(const char*) y std::string (vea los comentarios a continuación sobre std::find_first_of )

wchar_t es de 2 bytes (UTF16) en Windows. Pero en otras máquinas es de 4 bytes (UTF32). Esto hace que las cosas sean más confusas.

Para UTF32, puede usar std::u32string que es igual en diferentes sistemas.

Podría considerar convertir UTF8 a UTF32, porque de esa manera cada carácter es siempre de 4 bytes, y podría pensar que las operaciones de cadena serán más fáciles. Pero eso rara vez es necesario.

UTF8 está diseñado para que los caracteres ASCII entre 0 y 128 no se utilicen para representar otros puntos de código Unicode. Eso incluye la secuencia de escape ''/' , los especificadores de formato de printf y los caracteres de análisis comunes como ,

Considere la siguiente cadena UTF8. Digamos que quieres encontrar la coma

std::string str = u8"汉,🙂"; //3 code points represented by 8 bytes

El valor ASCII para la coma es 44 , y se garantiza que str contiene solo un byte cuyo valor es 44 . Para encontrar la coma, simplemente puede usar cualquier función estándar en C o C ++ para buscar '',''

Para encontrar , puede buscar la cadena u8"汉" ya que este punto de código no se puede representar como un solo carácter.

Algunas funciones de C y C ++ no funcionan correctamente con UTF8. Éstos incluyen

strtok strspn std::find_first_of

El argumento de las funciones anteriores es un conjunto de caracteres, no una cadena real.

Así que str.find_first_of(u8"汉") no funciona. Debido a que u8"汉" es de 3 bytes, y find_first_of buscará cualquiera de esos bytes. Existe la posibilidad de que uno de esos bytes se utilice para representar un punto de código diferente.

Por otro lado, str.find_first_of(u8",;abcd") es seguro, porque todos los caracteres en el argumento de búsqueda son ASCII (la misma str puede contener cualquier carácter Unicode)

En casos raros, se puede requerir UTF32 (¡aunque no puedo imaginar dónde!) Puede usar std::codecvt para convertir UTF8 a UTF32 para ejecutar las siguientes operaciones:

std::u32string u32 = U"012汉"; //4 code points, represented by 4 elements cout << u32.find_first_of(U"汉") << endl; //outputs 3 cout << u32.find_first_of(U''汉'') << endl; //outputs 3

Nota al margen:

Debe utilizar "Unicode en todas partes" , no "UTF8 en todas partes" .

En Linux, Mac, etc. usa UTF8 para Unicode.

En Windows, use UTF16 para Unicode. Los programadores de Windows usan UTF16, no hacen conversiones sin sentido de ida y vuelta a UTF8. Pero hay casos legítimos para usar UTF8 en Windows.

Los programadores de Windows tienden a usar UTF8 para guardar archivos, páginas web, etc. Así que eso es menos preocupante para los programadores que no son de Windows en términos de compatibilidad.

Al lenguaje en sí no le importa qué formato de Unicode desea utilizar, pero en términos prácticos, use un formato que coincida con el sistema en el que está trabajando.