He estado buscando una forma para convertir entre cadena Unicode tipos y llegó a través de este método. No sólo me no entender completamente el método (no hay comentarios), pero también el artículo implica que en el futuro va a ser mejor métodos.

Si este es el mejor método, podría usted por favor, señale lo que hace que funcione, y si no que me gustaría escuchar sugerencias para mejorar los métodos.

InformationsquelleAutor DrYap | 2011-08-29

3 Comentarios

  1. 87

    mbstowcs() y wcstombs() no necesariamente convertir a UTF-16 o UTF-32, que se convierten en wchar_t y sea cual sea la configuración regional wchar_t codificación. Todas las configuraciones regionales de Windows utiliza dos bytes wchar_t y UTF-16, así como la codificación, pero las otras grandes plataformas de uso 4 bytes wchar_t con UTF-32 (o incluso un no-codificación Unicode para algunas configuraciones regionales). Una plataforma que sólo admite un solo byte codificaciones podría incluso tener un byte de wchar_t y tener la codificación se diferencian por la configuración regional. Así wchar_t me parece una mala opción para la portabilidad y Unicode. *

    Algunas opciones que se han introducido en C++11; las nuevas especializaciones de std::codecvt, nueva codecvt clases, y una nueva plantilla para hacer uso de ellos para las conversiones muy cómodas.

    Primera de la nueva plantilla de clase para el uso de codecvt es std::wstring_convert. Una vez creada una instancia de un std::wstring_convert clase usted puede convertir fácilmente entre las cuerdas:

    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);

    Con el fin de hacer diferentes conversión sólo se necesita diferentes parámetros de la plantilla, uno de los cuales es un codecvt faceta. Aquí están algunos de los nuevos aspectos que son fáciles de usar con wstring_convert:

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

    Ejemplos del uso de estas:

    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,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");

    La nueva std::codecvt especializaciones son un poco más difíciles de usar debido a que tienen un protegidas destructor. Para evitar que la puede definir una subclase que tiene un destructor, o puede utilizar el std::use_facet función de la plantilla para obtener una existente codecvt instancia. También, un problema con estas especializaciones es que no se pueden utilizar en Visual Studio 2010 debido a la especialización de plantilla no funciona con typedef d tipos y que el compilador define char16_t y char32_t como typedefs. He aquí un ejemplo de definición de su propia subclase de codecvt:

    template <class internT, class externT, class stateT>
    struct codecvt : std::codecvt<internT,externT,stateT>
    { ~codecvt(){} };
    
    std::wstring_convert<codecvt<char16_t,char,std::mbstate_t>,char16_t> convert16;
    std::wstring_convert<codecvt<char32_t,char,std::mbstate_t>,char32_t> convert32;

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

    Tenga en cuenta que estas nuevas conversiones proporcionada por C++11 no incluye ninguna manera de convertir directamente entre UTF-32 y UTF-16. En lugar de ello sólo tienes que combinar dos instancias de std::wstring_convert.


    ***** Pensé que me gustaría añadir una nota en wchar_t y su propósito, para hacer hincapié en por qué no debería ser generalmente usados para Unicode o portátil internacionalizado código. La siguiente es una versión corta de mi respuesta https://stackoverflow.com/a/11107667/365496

    Lo que es wchar_t?

    wchar_t está definido de tal forma que cualquier configuración de la codificación char puede ser convertido a wchar_t donde cada wchar_t representa exactamente un punto de código:

    Tipo wchar_t es un tipo distinto cuyos valores pueden representar distintos códigos para todos los miembros de la extendido más grande del conjunto de caracteres especificado entre los locales soportados (22.3.1). — [basic.fundamentales] 3.9.1/5

    Este no requieren que wchar_t ser lo suficientemente grande como para representar a cualquier personaje de todas las localizaciones simultáneamente. Es decir, la codificación que se utiliza para wchar_t puede variar entre los locales. Lo que significa que no necesariamente pueden convertir una cadena a wchar_t el uso de una configuración regional y, a continuación, volver a convertir a char utilizar otra configuración regional.

    Ya que parece ser el principal uso en la práctica para wchar_t usted podría preguntarse qué es bueno para si que no.

    La intención original y el propósito de wchar_t era hacer de procesamiento de texto simple por definición es tal que se requiere de un uno-a-uno la asignación de una cadena de código unidades para el texto de los personajes, por lo tanto permitiendo el uso de la misma sencilla algoritmos utilizados con cadenas de caracteres ascii para trabajar con otros idiomas.

    Lamentablemente los requisitos en wchar_t asumir un uno-a-uno el mapeo entre los personajes y puntos de codificación para lograr esto. Unicode se rompe esa suposición, por lo que no se puede utilizar de forma segura wchar_t de texto simple algoritmos de cualquiera.

    Esto significa que el programa portátil puede utilizar wchar_t, ya sea como una representación común para el texto entre configuraciones, o para permitir el uso de un simple texto algoritmos.

    Lo que uso es wchar_t hoy?

    No mucho, para la portátil de código de todos modos. Si __STDC_ISO_10646__ está definido, entonces los valores de wchar_t directamente representan puntos de codificación de Unicode con los mismos valores en todas las localizaciones. Que hace que sea seguro para hacer el inter-regional de las conversiones se mencionó anteriormente. Sin embargo, no puede confiar sólo en él para decidir que usted puede utilizar wchar_t de esta manera porque, aunque la mayoría de las plataformas unix definir, Windows no a pesar de que Windows utiliza el mismo wchar_t regional en todas las localizaciones.

    La razón por la que Windows no definir __STDC_ISO_10646__ creo que es debido a que Windows use UTF-16, así como su wchar_t de codificación, y porque UTF-16 utiliza los pares suplentes para representar puntos de codificación mayores que U+FFFF, lo que significa que la codificación UTF-16 no satisfacen los requisitos para __STDC_ISO_10646__.

    Para la plataforma de código específico wchar_t puede ser más útil. Es esencialmente necesario en Windows (por ejemplo, algunos archivos simplemente no se puede abrir sin necesidad de utilizar wchar_t nombres de archivo), a pesar de que Windows es la única plataforma donde esto es cierto hasta donde yo sé (así que tal vez podemos pensar wchar_t como ‘Windows_char_t’).

    En retrospectiva, wchar_t está claro que no es útil para simplificar el manejo del texto, o como el almacenamiento de la configuración regional independiente de texto. El código Portable no debe intentar usarla para estos fines.

    • Muchas gracias por tan en profundidad de la respuesta, esto es exactamente lo que yo estaba buscando. Podría acabo de confirmar que UTF-16 y UTF-32 requeriría UTF-16 y UTF-8 y, a continuación, a UTF-32?
    • Sí, usted tiene que ir a través de la codificación UTF-8.
    • En realidad, puede ser una manera de ir directamente entre UTF-16 y UTF-32, pero no lo he utilizado así que no estoy seguro de todos los detalles. Echa un vistazo a otro de C++11 faceta: codecvt_utf16.
    • Yo tenía un ir en hacer esto, pero he tenido un problema con wstring_convert no existente. No trabajo con g++ todavía?
    • Por desgracia parece que stdlibc++ no ha llegado a este punto, incluso en su versión más reciente. Supongo que esto es lo que el artículo que enlaza a estaba diciendo. Así que lo que hace el código, en que el artículo es que stdlibc++’s std::codecvt puede utilizar libiconv. Echa un vistazo a ese tipo de Convertidor.h y mirar EncSt, codecvt_type, y cómo EncSt estado se inicializa.
    • Por CIERTO, esto es implmented en libc++ (no se trata aún de la biblioteca estándar de c++ para clang), así como de VS2010 (a excepción de la excepción, he observado).
    • He probado este (ideone.com/7u3si) con gcc-4.7.0-beta a partir de ayer. Si se implementa, tengo que hacer algo seriamente mal. Me puedes dar una pista? Ambos, el ideone-gcc-4.5 y la mía gcc-4.7.0-svn «no se puede encontrar <codecvt>». También en mi instalación $ include/c++/4.7.0$ find . -type f | xargs grep wstring_convert no revela nada.
    • parece que todavía no está implementado en el gcc. Sólo MSVC y libc++.
    • wstring_convert y amigos han sido desaprobados en C++17
    • Que tienen, y por qué, en mi opinión, es una mala razón.

  2. 12

    He escrito funciones auxiliares para convertir a/de cadenas de caracteres UTF8 (C++11):

    #include <string>
    #include <locale>
    #include <codecvt>
    
    using namespace std;
    
    template <typename T>
    string toUTF8(const basic_string<T, char_traits<T>, allocator<T>>& source)
    {
        string result;
    
        wstring_convert<codecvt_utf8_utf16<T>, T> convertor;
        result = convertor.to_bytes(source);
    
        return result;
    }
    
    template <typename T>
    void fromUTF8(const string& source, basic_string<T, char_traits<T>, allocator<T>>& result)
    {
        wstring_convert<codecvt_utf8_utf16<T>, 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);
    }
  3. -2

    Que yo sepa, C++ proporciona ningún método estándar para convertir desde o a UTF-32. Sin embargo, para UTF-16 no son los métodos mbstowcs (Multi-Byte a la Amplia cadena de caracteres), y a la inversa, wcstombs.

    Si usted necesita UTF-32, necesitas iconv, que es en POSIX 2001 pero no en el estándar de C, por lo que en Windows vas a necesitar un reemplazo como libiconv.

    He aquí un ejemplo de cómo usar mbstowcs:

    #include <string>
    #include <iostream>
    #include <stdlib.h>
    
    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 va como esto:

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

    Ser quisquilloso: Sí, lo sé, el tamaño de wchar_t es definido por la implementación, por lo que podría ser de 4 Bytes (UTF-32). Sin embargo, no sé un compilador que lo hace.

    • GCC en Linux usa UTF-32 para wchar_t.
    • A lo que yo sé, Windows es la única plataforma común que utiliza UTF-16 para wstring.
    • Probablemente no cuenta como «comunes», pero creo AIX utiliza 2 bytes wchar_t y UTF-16.
    • El problema con la función de inversión es que usted puede ser que necesite un buffer con más elementos de los que hay caracteres en la cadena original, por ejemplo, Si se convierte en una gran cadena con el Japonés, y fue convertido a S-JIS, el texto se trunca. Si usted llama wcstombs con NULL como primer argumento, entonces la función devuelve el tamaño del búfer necesario para almacenar todos los caracteres en la cadena original. También, antes de C++11, no había ninguna garantía de que los elementos de una std::string se almacenan de forma contigua, y de C++11, hay std::codecvt que hace que todo este calvario trivial.

Dejar respuesta

Please enter your comment!
Please enter your name here