Convierta entre cadena, u16string y u32string

He estado buscando una forma de convertir entre los tipos de cadena Unicode y encontré este método . No solo no entiendo completamente el método (no hay comentarios) sino que también el artículo implica que en el futuro habrá mejores métodos.

Si este es el mejor método, ¿podría indicar qué lo hace funcionar? Si no, me gustaría recibir sugerencias para mejores métodos.

mbstowcs() y wcstombs() no necesariamente se convierten a UTF-16 o UTF-32, se convierten a wchar_t y cualquiera que sea la encoding wchar_t locale. Todos los locales de Windows usan un wchar_t dos bytes y UTF-16 como encoding, pero las otras plataformas principales usan un wchar_t 4 bytes con UTF-32 (o incluso una encoding que no es Unicode para algunas configuraciones regionales). Una plataforma que solo admita codificaciones de un solo byte podría tener incluso un octeto wchar_t y la encoding diferir según la configuración regional. Entonces, wchar_t parece que wchar_t es una mala elección para la portabilidad y Unicode. *

Algunas mejores opciones se han introducido en C ++ 11; nuevas especializaciones de std :: codecvt, nuevas clases de codecvt y una nueva plantilla para hacer que el uso de conversiones sea muy conveniente.

Primero, la nueva clase de plantilla para usar codecvt es std :: wstring_convert. Una vez que haya creado una instancia de una clase std :: wstring_convert, puede convertir fácilmente entre cadenas:

 std::wstring_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16 std::string utf8_string = u8"This string has UTF-8 content"; std::u16string utf16_string = convert.from_bytes(utf8_string); std::string another_utf8_string = convert.to_bytes(utf16_string); 

Para hacer una conversión diferente, solo necesitas diferentes parámetros de plantilla, uno de los cuales es una faceta codecvt. Aquí hay algunas facetas nuevas que son fáciles de usar con wstring_convert:

 std::codecvt_utf8_utf16 // converts between UTF-8 <-> UTF-16 std::codecvt_utf8 // converts between UTF-8 <-> UTF-32 std::codecvt_utf8 // converts between UTF-8 <-> UCS-2 (warning, not UTF-16! Don't bother using this one) 

Ejemplos de usar estos:

 std::wstring_convert,char16_t> convert; std::string a = convert.to_bytes(u"This string has UTF-16 content"); std::u16string b = convert.from_bytes(u8"blah blah blah"); 

Las nuevas especializaciones de std :: codecvt son un poco más difíciles de usar porque tienen un destructor protegido. Para evitarlo, puede definir una subclase que tenga un destructor, o puede usar la función de plantilla std :: use_facet para obtener una instancia de codecvt existente. Además, un problema con estas especializaciones es que no puede usarlas en Visual Studio 2010 porque la especialización de plantillas no funciona con tipos typedef’d y el comstackdor define char16_t y char32_t como typedefs. Aquí hay un ejemplo de definición de su propia subclase de codecvt:

 template  struct codecvt : std::codecvt { ~codecvt(){} }; std::wstring_convert,char16_t> convert16; std::wstring_convert,char32_t> convert32; 

La especialización char16_t se convierte entre UTF-16 y UTF-8. La especialización char32_t, UTF-32 y UTF-8.

Tenga en cuenta que estas nuevas conversiones proporcionadas por C ++ 11 no incluyen ninguna forma de convertir directamente entre UTF-32 y UTF-16. En su lugar, solo tiene que combinar dos instancias de std :: wstring_convert.


***** Pensé en agregar una nota sobre wchar_t y su propósito, para enfatizar por qué generalmente no se debe usar para Unicode o código internacionalizado portátil. La siguiente es una versión corta de mi respuesta https://stackoverflow.com/a/11107667/365496

¿Qué es wchar_t?

wchar_t se define de tal manera que la encoding de caracteres de cualquier localidad se puede convertir a wchar_t donde cada wchar_t representa exactamente un punto de código:

Escriba wchar_t es un tipo distinto cuyos valores pueden representar códigos distintos para todos los miembros del conjunto de caracteres ampliado más grande especificado entre las configuraciones regionales admitidas (22.3.1). – [basic.fundamental] 3.9.1 / 5

Esto no requiere que wchar_t sea lo suficientemente grande como para representar cualquier carácter de todas las configuraciones regionales simultáneamente. Es decir, la encoding utilizada para wchar_t puede diferir entre las configuraciones regionales. Lo que significa que no necesariamente puede convertir una cadena a wchar_t usando una configuración regional y luego convertir de nuevo a char usando otra configuración regional.

Dado que ese parece ser el uso principal en la práctica para wchar_t, quizás te preguntes para qué sirve si no es así.

La intención y el propósito original de wchar_t era simplificar el procesamiento de texto definiéndolo de forma que requiera un mapeo uno a uno desde las unidades de código de una cadena a los caracteres del texto, permitiendo así el uso de los mismos algoritmos simples utilizados con las cadenas ASCII para trabajar con otros idiomas

Lamentablemente, los requisitos de wchar_t presuponen un mapeo uno a uno entre caracteres y puntos de código para lograr esto. Unicode rompe esa suposición, por lo que tampoco puedes usar wchar_t para algoritmos de texto simples.

Esto significa que el software portátil no puede usar wchar_t como una representación común de texto entre configuraciones regionales, o para permitir el uso de algoritmos de texto simples.

¿De qué sirve wchar_t hoy?

No mucho, para el código portátil de todos modos. Si se define __STDC_ISO_10646__ , los valores de wchar_t representan directamente los puntos de código Unicode con los mismos valores en todas las configuraciones regionales. Eso hace que sea seguro hacer las conversiones entre locaciones mencionadas anteriormente. Sin embargo, no puede confiar únicamente en que decida que puede usar wchar_t de esta manera porque, aunque la mayoría de las plataformas de UNIX lo definen, Windows no lo hace aunque Windows usa la misma configuración regional wchar_t en todas las configuraciones regionales.

La razón por la que Windows no define __STDC_ISO_10646__ Creo que es porque Windows usa UTF-16 como su encoding wchar_t, y porque UTF-16 usa pares de sustitución para representar puntos de código mayores que U + FFFF, lo que significa que UTF-16 no satisface la requisitos para __STDC_ISO_10646__ .

Para el código específico de la plataforma, wchar_t puede ser más útil. Esencialmente se requiere en Windows (por ejemplo, algunos archivos simplemente no se pueden abrir sin usar nombres de archivo wchar_t), aunque Windows es la única plataforma donde esto es cierto hasta donde yo sé (así que tal vez podamos pensar en wchar_t como ‘Windows_char_t’).

En retrospectiva, wchar_t claramente no es útil para simplificar el manejo de texto, o como almacenamiento para texto independiente de la configuración regional. El código portátil no debe intentar usarlo para estos fines.

Escribí funciones de ayuda para convertir a / desde cadenas UTF8 (C ++ 11):

 #include  #include  #include  using namespace std; template  string toUTF8(const basic_string, allocator>& source) { string result; wstring_convert, T> convertor; result = convertor.to_bytes(source); return result; } template  void fromUTF8(const string& source, basic_string, allocator>& result) { wstring_convert, T> convertor; result = convertor.from_bytes(source); } 

Ejemplo de uso:

 // Unicode <-> UTF8 { wstring uStr = L"Unicode string"; string str = toUTF8(uStr); wstring after; fromUTF8(str, after); assert(uStr == after); } // UTF16 <-> UTF8 { u16string uStr; uStr.push_back('A'); string str = toUTF8(uStr); u16string after; fromUTF8(str, after); assert(uStr == after); } 

Hasta donde yo sé, C ++ no proporciona métodos estándar para convertir desde o hacia UTF-32. Sin embargo, para UTF-16 existen los métodos mbstowcs (cadena de caracteres Multi-Byte a Wide), y los wcstombs inversos.

Si también necesita UTF-32, necesita iconv , que está en POSIX 2001 pero no en C estándar, por lo que en Windows necesitará un reemplazo como libiconv .

Aquí hay un ejemplo sobre cómo usar mbstowcs :

 #include  #include  #include  using namespace std; wstring widestring(const string &text); int main() { string text; cout << "Enter something: "; cin >> text; wcout << L"You entered " << widestring(text) << ".\n"; return 0; } wstring widestring(const string &text) { wstring result; result.resize(text.length()); mbstowcs(&result[0], &text[0], text.length()); return result; } 

El reverso es así:

 string mbstring(const wstring &text) { string result; result.resize(text.length()); wcstombs(&result[0], &text[0], text.length()); return result; } 

Nitpick: Sí, lo sé, el tamaño de wchar_t está definido por la implementación, por lo que podría ser de 4 Bytes (UTF-32). Sin embargo, no conozco un comstackdor que haga eso.