如何将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,则需要将其更改为正在使用的相应编码:
解决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或其他一些图书馆来处理这些细节。
代码有两个问题:
-
const std::string s( ws.begin(), ws.end() );
不需要将宽字符正确地映射到窄字符。 最有可能的是,每个宽字符将只是char
。
这个问题的解决已经在kem的答案中给出了,并涉及到locale的ctype
方面的narrow
function。 -
您在同一个程序
std::wcout
输出写入std::cout
和std::wcout
。cout
和wcout
都与同一个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
可以用string
, char const*
, wstring
或wchar_t const*
进行初始化,并且可以通过或隐式转换为string
或wstring
(可以传递给函数采取任一)。
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"