wchar_t c++ unicode stl wstring

c++ - wchar_t - string wstring difference



Cómo convertir wstring en una cadena? (14)

Aquí hay una solución resuelta 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.

La pregunta es cómo convertir wstring en una cadena?

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 solo es:

std::wstring = Hello

¿Hay algo mal en el ejemplo? ¿Puedo hacer la conversión como arriba?

EDITAR

El 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; }

El resultado es:

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

por lo tanto, el stringstream no se puede usar para convertir wstring en string.


Como señaló Cubbi en uno de los comentarios, std::wstring_convert (C ++ 11) proporciona una solución sencilla y ordenada (debe <codecvt> #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 darme cuenta de esto.

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

actualización (2013.11.28)

Se pueden establecer algunos liners como tal (Gracias Guss por su comentario):

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

Las funciones de Wrapper se pueden expresar así: (Gracias ArmanSchwarz por tu 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: existe cierta controversia sobre si string / wstring debe pasar a funciones como referencias o como literales (debido a C ++ 11 y actualizaciones del compilador). Dejaré la decisión a la persona que 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 necesitarás cambiarlo a la codificación apropiada que estés usando:

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


Creo que la forma oficial sigue siendo ir por codecvt facetas del codecvt (se necesita algún tipo de traducción que tenga en cuenta 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 usan esta maquinaria en la actualidad y cuántos simplemente piden punteros a la memoria y dejan que la ICU o alguna otra biblioteca maneje los detalles sangrientos.


En caso de que alguien más esté interesado: necesitaba una clase que pudiera usarse de manera intercambiable dondequiera que se esperara una string o una string wstring . La siguiente clase convertible_string , basada en la solución de dk123 , se puede inicializar con una string , char const* , wstring o wchar_t const* y se puede asignar por o convertir implícitamente a una string o wstring (por lo que se puede pasar a funciones eso toma 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_; };


En lugar de incluir locale y todas esas cosas elegantes, si sabes por FACT tu cadena es convertible solo haz 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 here


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

Realizo la misma función con el uso de new, delete [], pero es más lento que esto.

Esto puede ayudar a 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 bytes múltiples, 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); }


Esta solución está inspirada en la solución de dk123, pero usa codecvt facet dependiente de la configuración regional. El resultado está en la cadena codificada de la configuración regional en lugar de utf8 (si no está configurada 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 encontré que puedo obtener una faceta correcta desde std :: locale usando la función std :: use_facet () con el tipo de letra correcto. Espero que esto ayude.


Estoy usando debajo para convertir wstring en string.

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;


Hay dos problemas con el código:

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

  2. Está escribiendo salida para std::cout y std::wcout en el mismo programa. Tanto cout como wcout están asociados con la misma secuencia ( stdout ) y los resultados de utilizar la misma secuencia como una secuencia orientada a bytes (como cout hace) y una secuencia orientada a gran medida (como wcout hace) no están definidos.
    La mejor opción es evitar mezclar resultados estrechos y anchos con el mismo flujo (subyacente). Para stdout / cout / wcout , puede intentar cambiar la orientación de stdout cuando cambie entre salida angosta y ancha (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; }


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 cuidado de que no haya ninguna conversión de juego de caracteres aquí. Lo que hace es simplemente asignar cada iterado wchar_t a un char : una conversión wchar_t . Utiliza el std :: string c''tor :

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

Como se afirma en los comentarios:

los valores 0-127 son idénticos en prácticamente todas las codificaciones, por lo que truncar los valores que son todos menos de 127 resulta en el mismo texto. Coloca un personaje chino y verás el error.

-

los valores 128-255 de la página de códigos de Windows 1252 (el valor predeterminado de Windows) y los valores 128-255 de Unicode son en su mayoría iguales, por lo que si esa es la página de códigos que está usando, la mayoría de esos caracteres se truncarán a los valores correctos. (Esperaba totalmente que á y õ trabajasen, 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 , œ , ž , Ÿ , ...


También podrías usar el método estrecho de la faceta tipo c 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]); }


En el momento de escribir esta respuesta, la búsqueda número uno de google para "convert string wstring" lo ubicaría en esta página. Mi respuesta muestra cómo convertir cadena a wstring, aunque esta NO es la pregunta real, y probablemente debería eliminar esta respuesta, pero se considera mala. Es posible que desee pasar a esta respuesta de , que ahora tiene una clasificación más alta que esta página.

Aquí hay una manera de combinar cadenas, wstring y constantes de cadenas mixtas en wstring. Use 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();


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


// 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"