Cómo convertir wstring en cadena?


La pregunta es cómo convertir wstring a string?

Tengo el siguiente ejemplo:

#include <string>
#include <iostream>

int main()
{
    std::wstring ws = L"Hello";
    std::string s( ws.begin(), ws.end() );

  //std::cout <<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;
    std::cout <<"std::string =     "<<s<<std::endl;
}

La salida con la línea comentada es:

std::string =     Hello
std::wstring =    Hello
std::string =     Hello

Pero sin es solo:

std::wstring =    Hello

¿Hay algo malo en el ejemplo? ¿Puedo hacer la conversión como la anterior?

EDITAR

Nuevo ejemplo (teniendo en cuenta algunas respuestas) es

#include <string>
#include <iostream>
#include <sstream>
#include <locale>

int main()
{
    setlocale(LC_CTYPE, "");

    const std::wstring ws = L"Hello";
    const std::string s( ws.begin(), ws.end() );

    std::cout<<"std::string =     "<<s<<std::endl;
    std::wcout<<"std::wstring =    "<<ws<<std::endl;

    std::stringstream ss;
    ss << ws.c_str();
    std::cout<<"std::stringstream =     "<<ss.str()<<std::endl;
}

La salida es:

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c

Por lo tanto, el stringstream no se puede usar para convertir wstring en cadena.

Author: jleahy, 2011-01-26

15 answers

Aquí hay una solución elaborada basada en las otras sugerencias:

#include <string>
#include <iostream>
#include <clocale>
#include <locale>
#include <vector>

int main() {
  std::setlocale(LC_ALL, "");
  const std::wstring ws = L"ħëłlö";
  const std::locale locale("");
  typedef std::codecvt<wchar_t, char, std::mbstate_t> converter_type;
  const converter_type& converter = std::use_facet<converter_type>(locale);
  std::vector<char> to(ws.length() * converter.max_length());
  std::mbstate_t state;
  const wchar_t* from_next;
  char* to_next;
  const converter_type::result result = converter.out(state, ws.data(), ws.data() + ws.length(), from_next, &to[0], &to[0] + to.size(), to_next);
  if (result == converter_type::ok or result == converter_type::noconv) {
    const std::string s(&to[0], to_next);
    std::cout <<"std::string =     "<<s<<std::endl;
  }
}

Esto generalmente funcionará para Linux, pero creará problemas en Windows.

 28
Author: Philipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-26 14:52:28

Como Cubbi señaló en uno de los comentarios, std::wstring_convert (C++11) proporciona una solución simple y ordenada (es necesario #include <locale> y <codecvt>):

wstring string_to_convert;

//setup converter
using convert_type = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_type, wchar_t> converter;

//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
std::string converted_str = converter.to_bytes( string_to_convert );

Estaba usando una combinación de wcstombs y tediosa asignación/desasignación de memoria antes de que me topara con esto.

Http://en.cppreference.com/w/cpp/locale/wstring_convert

Actualizar(2013.11.28)

One liners puede ser declarado como tal (Gracias Guss por su comentario):

std::wstring str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes("some string");

Envoltura las funciones se pueden indicar así: (Gracias ArmanSchwarz por su comentario)

wstring s2ws(const std::string& str)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.from_bytes(str);
}

string ws2s(const std::wstring& wstr)
{
    using convert_typeX = std::codecvt_utf8<wchar_t>;
    std::wstring_convert<convert_typeX, wchar_t> converterX;

    return converterX.to_bytes(wstr);
}

Nota: hay cierta controversia sobre si string/wstring debe pasarse a funciones como referencias o como literales (debido a C++11 y actualizaciones del compilador). Dejaré la decisión a la persona que la implementa, pero vale la pena saberlo.

Nota: Estoy usando std::codecvt_utf8 en el código anterior, pero si no estás usando UTF-8 tendrás que cambiarlo a la codificación apropiada que estás usando:

Http://en.cppreference.com/w/cpp/header/codecvt

 239
Author: dk123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-04 13:35:15

Solución de: http://forums.devshed.com/c-programming-42/wstring-to-string-444006.html

std::wstring wide( L"Wide" ); 
std::string str( wide.begin(), wide.end() );

// Will print no problemo!
std::cout << str << std::endl;

Tenga en cuenta que no hay ninguna conversión de conjuntos de caracteres que esté sucediendo aquí en absoluto. Lo que esto hace es simplemente asignar cada iteración wchar_t a un char - una conversión truncante. Utiliza el std::string c tor:

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

Como se indica en los comentarios:

Los valores 0-127 son idénticos en prácticamente todas las truncar los valores que son todos inferiores a 127 dan como resultado el mismo texto. Poner en un carácter chino y verás el fracaso.

-

Los valores 128-255 de la página de código de Windows 1252 (el Inglés de Windows por defecto) y los valores 128-255 de unicode son en su mayoría los mismos, por lo que si esa es la página de código que está utilizando la mayoría de esos caracteres deben ser truncado a los valores correctos. (Esperaba totalmente á y õ trabajar, Sé que nuestro código en el trabajo se basa en esto para é, que pronto arreglaré)

Y tenga en cuenta que los puntos de código en el rango 0x80 - 0x9F en Win1252 no funcionarán. Esto incluye , œ, ž, Ÿ, ...

 112
Author: namar0x0309,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-02 09:08:16

En lugar de incluir la configuración regional y todas esas cosas sofisticadas, si sabe de HECHO que su cadena es convertible, simplemente haga esto:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  wstring w(L"bla");
  string result;
  for(char x : w)
    result += x;

  cout << result << '\n';
}

Ejemplo en vivo aquí

 11
Author: Justin Kirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-22 08:05:12

Creo que el camino oficial aún está por recorrer a través de codecvt facetas (necesita algún tipo de traducción consciente de la configuración regional), como en

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
  in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

O algo así, no tengo código de trabajo por ahí. Pero no estoy seguro de cuántas personas en estos días usan esa maquinaria y cuántas simplemente piden punteros a la memoria y dejan que la UCI o alguna otra biblioteca maneje los detalles sangrientos.

 7
Author: Christopher Creutzig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-26 12:11:29

También podrías usar el método estrecho de la faceta ctype directamente:

#include <clocale>
#include <locale>
#include <string>
#include <vector>

inline std::string narrow(std::wstring const& text)
{
    std::locale const loc("");
    wchar_t const* from = text.c_str();
    std::size_t const len = text.size();
    std::vector<char> buffer(len + 1);
    std::use_facet<std::ctype<wchar_t> >(loc).narrow(from, from + len, '_', &buffer[0]);
    return std::string(&buffer[0], &buffer[len]);
}
 6
Author: legalize,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-07 21:58:53

En el momento de escribir esta respuesta, la búsqueda número uno de Google para "convertir cadena wstring" te llevaría a esta página. Mi respuesta muestra cómo convertir string a wstring, aunque esta NO es la pregunta real, y probablemente debería eliminar esta respuesta, pero se considera mala forma. Es posible que desee saltar a esta respuesta de StackOverflow, que ahora está mejor clasificada que esta página.


Aquí hay una manera de combinar constantes de cadena, wstring y cadena mixta a wstring. Utilice la clase wstringstream.

#include <sstream>

std::string narrow = "narrow";
std::wstring wide = "wide";

std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();
 6
Author: Mark Lakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:13

Hay dos problemas con el código:

  1. La conversión en const std::string s( ws.begin(), ws.end() ); no es necesaria para asignar correctamente los caracteres anchos a su contraparte estrecha. Lo más probable es que cada carácter ancho sea encasillado a char.
    La resolución de este problema ya está dada en la respuesta de kem e involucra la función narrow de la faceta ctype de la localización.

  2. Está escribiendo la salida tanto a std::cout como a std::wcout en el mismo programa. cout y wcout están asociados con el mismo flujo (stdout) y los resultados de usar el mismo flujo tanto como un flujo orientado a bytes (como lo hace cout) como un flujo orientado a ancho (como lo hace wcout) no están definidos.
    La mejor opción es evitar mezclar salida estrecha y amplia a la misma corriente (subyacente). Para stdout/cout/wcout, puede intentar cambiar la orientación de stdout al cambiar entre salida ancha y estrecha (o viceversa):

    #include <iostream>
    #include <stdio.h>
    #include <wchar.h>
    
    int main() {
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
        fwide(stdout, -1); // switch to narrow
        std::cout << "narrow" << std::endl;
        fwide(stdout, 1); // switch to wide
        std::wcout << L"wide" << std::endl;
    }
    
 5
Author: Bart van Ingen Schenau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:39

En mi caso, tengo que usar multibyte character (MBCS), y quiero usar std::string y std::wstring. Y no puede usar c++11. Así que uso mbstowcs y wcstombs.

Hago la misma función con el uso de nuevo, eliminar [], pero es más lento que esto.

Esto puede ayudar Cómo: Convertir Entre Varios tipos de Cadenas

EDITAR

Sin embargo, en caso de convertir a wstring y la cadena de origen no es un alfabeto y una cadena de múltiples bytes, no está funcionando. Así que cambio wcstombs a WideCharToMultiByte.

#include <string>

std::wstring get_wstr_from_sz(const char* psz)
{
    //I think it's enough to my case
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    size_t len = strlen(psz) + 1;

    if (len >= sizeof(buf) / sizeof(wchar_t))
    {
        pbuf = L"error";
    }
    else
    {
        size_t converted;
        mbstowcs_s(&converted, buf, psz, _TRUNCATE);
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wsz(const wchar_t* pwsz)
{
    char buf[0x400];
    char *pbuf = buf;
    size_t len = wcslen(pwsz)*2 + 1;

    if (len >= sizeof(buf))
    {
        pbuf = "error";
    }
    else
    {
        size_t converted;
        wcstombs_s(&converted, buf, pwsz, _TRUNCATE);
    }

    return std::string(pbuf);
}

EDITAR para usar ' MultiByteToWideChar 'en lugar de'wcstombs'

#include <Windows.h>
#include <boost/shared_ptr.hpp>
#include "string_util.h"

std::wstring get_wstring_from_sz(const char* psz)
{
    int res;
    wchar_t buf[0x400];
    wchar_t *pbuf = buf;
    boost::shared_ptr<wchar_t[]> shared_pbuf;

    res = MultiByteToWideChar(CP_ACP, 0, psz, -1, buf, sizeof(buf)/sizeof(wchar_t));

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);

        shared_pbuf = boost::shared_ptr<wchar_t[]>(new wchar_t[res]);

        pbuf = shared_pbuf.get();

        res = MultiByteToWideChar(CP_ACP, 0, psz, -1, pbuf, res);
    }
    else if (0 == res)
    {
        pbuf = L"error";
    }

    return std::wstring(pbuf);
}

std::string get_string_from_wcs(const wchar_t* pcs)
{
    int res;
    char buf[0x400];
    char* pbuf = buf;
    boost::shared_ptr<char[]> shared_pbuf;

    res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, buf, sizeof(buf), NULL, NULL);

    if (0 == res && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    {
        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, NULL, 0, NULL, NULL);

        shared_pbuf = boost::shared_ptr<char[]>(new char[res]);

        pbuf = shared_pbuf.get();

        res = WideCharToMultiByte(CP_ACP, 0, pcs, -1, pbuf, res, NULL, NULL);
    }
    else if (0 == res)
    {
        pbuf = "error";
    }

    return std::string(pbuf);
}
 3
Author: heon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-04 09:45:10

Esta solución está inspirada en la solución de dk123, pero utiliza la faceta codecvt dependiente de la configuración regional. El resultado es una cadena codificada en la configuración regional en lugar de utf8 (si no se establece como configuración regional):

std::string w2s(const std::wstring &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
}

std::wstring s2w(const std::string &var)
{
   static std::locale loc("");
   auto &facet = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(loc);
   return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
}

Lo estaba buscando, pero no puedo encontrarlo. Finalmente descubrí que puedo obtener la faceta correcta de std::locale usando la función std::use_facet() con el nombre de tipo correcto. Espero que esto ayude.

 2
Author: Vizor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-27 14:57:25

En caso de que alguien más esté interesado: Necesitaba una clase que pudiera usarse indistintamente donde se esperaba un string o wstring. La siguiente clase convertible_string, basada en la solución de dk123 , se puede inicializar con string, char const*, wstring o wchar_t const* y se puede asignar a por o implícitamente convertido a una string o wstring (por lo que se puede pasar a una funciones que toman cualquiera).

class convertible_string
{
public:
    // default ctor
    convertible_string()
    {}

    /* conversion ctors */
    convertible_string(std::string const& value) : value_(value)
    {}
    convertible_string(char const* val_array) : value_(val_array)
    {}
    convertible_string(std::wstring const& wvalue) : value_(ws2s(wvalue))
    {}
    convertible_string(wchar_t const* wval_array) : value_(ws2s(std::wstring(wval_array)))
    {}

    /* assignment operators */
    convertible_string& operator=(std::string const& value)
    {
        value_ = value;
        return *this;
    }
    convertible_string& operator=(std::wstring const& wvalue)
    {
        value_ = ws2s(wvalue);
        return *this;
    }

    /* implicit conversion operators */
    operator std::string() const { return value_; }
    operator std::wstring() const { return s2ws(value_); }
private:
    std::string value_;
};
 1
Author: James Hirschorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:20
#include <boost/locale.hpp>
namespace lcv = boost::locale::conv;

inline std::wstring fromUTF8(const std::string& s)
{ return lcv::utf_to_utf<wchar_t>(s); }

inline std::string toUTF8(const std::wstring& ws)
{ return lcv::utf_to_utf<char>(ws); }
 0
Author: deep125,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-30 16:01:59

Codificación predeterminada en:

  • Windows UTF-16.
  • Linux UTF-8.
  • macOS UTF-8.

Este código tiene dos formas para convertir std::string a std::wstring y std::wstring a std::string. Si niega # if defined WIN32, obtendrá el mismo resultado.

1. std:: string a std:: wstring

MultiByteToWideChar WinAPI

_mbstowcs_s_l

#if defined WIN32
#include <windows.h>
#endif

std::wstring StringToWideString(std::string str)
{
    if (str.empty())
    {
        return std::wstring();
    }
    size_t len = str.length() + 1;
    std::wstring ret = std::wstring(len, 0);
#if defined WIN32
    int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len);
    ret.resize(size);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

2. std::wstring a std:: string

WideCharToMultiByte WinAPI

_wcstombs_s_l

std::string WidestringToString(std::wstring wstr)
{
    if (wstr.empty())
    {
        return std::string();
    }
#if defined WIN32
    int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
    std::string ret = std::string(size, 0);
    WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL);
#else
    size_t size = 0;
    _locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
    errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc);
    std::string ret = std::string(size, 0);
    err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc);
    _free_locale(lc);
    ret.resize(size - 1);
#endif
    return ret;
}

3. En Windows necesita imprimir unicode, usando WinAPI.

WriteConsole

#if defined _WIN32
    void WriteLineUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::string s)
    {
        std::wstring unicode = StringToWideString(s);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
    }

    void WriteLineUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
        std::cout << std::endl;
    }

    void WriteUnicode(std::wstring ws)
    {
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
    }

4. En el programa principal.

#if defined _WIN32
int wmain(int argc, WCHAR ** args)
#else
int main(int argc, CHAR ** args)
#endif
{
    std::string source = u8"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča";
    std::wstring wsource = L"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča";

    WriteLineUnicode(L"@" + StringToWideString(source) + L"@");
    WriteLineUnicode("@" + WidestringToString(wsource) + "@");
    return EXIT_SUCCESS;
}

5. Por último, necesita un soporte potente y completo para caracteres unicode en la consola. Recomiendo ConEmu y establecer como terminal predeterminado en Windows. Necesitas enganchar Visual Studio a ConEmu. Recuerde que el archivo exe de Visual Studio es devenv.exe

Probado en Visual Studio 2017 con VC++; std=c++17.

Resultado

Resultado1

 0
Author: Joma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-24 23:13:52

Estoy usando a continuación para convertir wstring a cadena.

std::string strTo;
char *szTo = new char[someParam.length() + 1];
szTo[someParam.size()] = '\0';
WideCharToMultiByte(CP_ACP, 0, someParam.c_str(), -1, szTo, (int)someParam.length(), NULL, NULL);
strTo = szTo;
delete szTo;
 -1
Author: impulse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-03 17:03:34
// Embarcadero C++ Builder 

// convertion string to wstring
string str1 = "hello";
String str2 = str1;         // typedef UnicodeString String;   -> str2 contains now u"hello";

// convertion wstring to string
String str2 = u"hello";
string str1 = UTF8string(str2).c_str();   // -> str1 contains now "hello"
 -3
Author: necips,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-11 11:27:57