如何将wstring转换为string?

问题是如何将wstring转换为string?

我有下个例子:

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

输出注释掉的是:

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

但没有只是:

 std::wstring = Hello 

这个例子有什么不对吗? 我可以做如上所述的转换吗?

编辑

新的例子(考虑到一些答案)是

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

输出是:

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

因此stringstream不能用来把wstring转换成string。

以下是基于其他build议的解决scheme:

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

这通常适用于Linux,但会在Windows上创build问题。

正如Cubbi在其中一个注释中指出的, std::wstring_convert (C ++ 11)提供了一个简洁的解决scheme(您需要#include <locale><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 ); 

在我遇到这个之前,我正在使用wcstombs和冗长的内存分配/重新分配的组合。

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

更新(2013年11月28日)

一个衬里可以这样说(谢谢你的评论):

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

包装函数可以这样陈述:(谢谢ArmanSchwarz的评论)

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

注意:关于string / wstring是否应该作为引用或文字(由于C ++ 11和编译器更新)传递给函数,存在一些争议。 我会把这个决定留给这个人来执行,但这是值得了解的。

注意:我在上面的代码中使用了std::codecvt_utf8 ,但是如果您不使用UTF-8,则需要将其更改为正在使用的相应编码:

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

解决scheme来自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; 

请注意 ,这里根本没有字符集转换。 这样做只是将每个迭代的wchar_t赋给一个char – 一个截断的转换。 它使用std :: string c'tor :

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

如评论中所述:

实际上在每个编码中值0-127是相同的,因此截断小于127的值导致相同的文本。 把一个汉字,你会看到失败。

windows代码页1252(Windows英文默认值)的值128-255和unicode的值128-255大部分是相同的,所以如果这是你使用的代码页,那么大多数这些字符应该被截断为正确的值。 (我完全期待á和õ的工作,我知道我们的代码在工作中依赖于这个é,我将很快修复)

请注意, Win1252中 0x80 - 0x9F范围内的代码将不起作用。 这包括œžŸ ,…

如果你知道FACT你的string是可转换的,只需要做到这一点,而不是包含locale和所有的花哨的东西,

 #include <iostream> #include <string> using namespace std; int main() { wstring w(L"bla"); string result; for(char x : w) result += x; cout << result << '\n'; } 

现场示例

你也可以直接使用ctype facet的narrow方法:

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

内联std ::string窄(std :: wstring常量和文本)
 {
     std :: locale const loc(“”);
     wchar_t const * from = text.c_str();
     std :: size_t const len = text.size();
     std :: vector <char>缓冲区(len + 1);
     std :: use_facet <std :: ctype <wchar_t>>(loc).narrow(from,from + len,'_',&buffer [0]);
    返回std :: string(&buffer [0],&buffer [len]);
 }

在写这个答案的时候,谷歌search“转换stringwstring”的头号将在这个页面上。 我的答案显示如何将string转换为wstring,虽然这不是实际的问题,我应该删除这个答案,但是这被认为是不好的forms。 你可能想跳转到这个StackOverflow的答案 ,现在比这个页面排名更高。


这是一种将string,wstring和混合string常量组合到wstring的方法。 使用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(); 

我相信官方的方式仍然是通过codecvt方面(你需要某种地区意识的翻译),如在

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

或类似的东西,我没有工作代码躺在周围。 但是我不确定现在有多less人使用这个机器,有多less人只是要求指向记忆,让ICU或其他一些图书馆来处理这些细节。

代码有两个问题:

  1. const std::string s( ws.begin(), ws.end() ); 不需要将宽字符正确地映射到窄字符。 最有可能的是,每个宽字符将只是char
    这个问题的解决已经在kem的答案中给出了,并涉及到locale的ctype方面的narrowfunction。

  2. 您在同一个程序std::wcout输出写入std::coutstd::wcoutcoutwcout都与同一个stream( stdout )相关联,并且使用同一个stream作为面向字节的stream(如cout )和面向广泛的stream(如wcout )的结果没有定义。
    最好的select是避免混合窄和宽的输出到相同的(底层)stream。 对于stdout / cout / wcout ,可以在宽输出和窄输出之间切换时尝试切换stdout的方向(反之亦然):

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

在我的情况下,我必须使用多字节字符(MBCS),我想要使用std :: string和std :: wstring。 而且不能使用c ++ 11。 所以我使用mbstowcs和wcstombs。

我使用新的,删除[],使相同的function,但它比这慢。

这可以帮助如何:在各种stringtypes之间进行转换

编辑

但是,如果转换为wstring和源string是没有字母和多字节string,它不起作用。 所以我把wcstombs改为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); } 

编辑使用“MultiByteToWideChar”而不是“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); } 

这个解决scheme是启发dk123的解决scheme,但使用与语言环境相关的codecvt方面。 结果是用locale编码的string而不是utf8(如果它没有设置为locale):

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

我正在寻找它,但我找不到它。 最后,我发现我可以从std :: locale使用正确的typename使用std :: use_facet()函数来获得正确的方面。 希望这可以帮助。

如果其他人感兴趣:我需要一个可以互换使用的类,无论是string还是wstring 。 基于dk123解决scheme的以下类convertible_string可以用stringchar const*wstringwchar_t const*进行初始化,并且可以通过或隐式转换为stringwstring (可以传递给函数采取任一)。

 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_; }; 
 #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"