问题是如何将wstring转换为字符串?
我还有一个例子:
#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
但是without只是:
std::wstring = Hello
这个例子中有什么问题吗?我可以像上面那样进行转换吗?
EDIT
新例子(考虑到一些答案)是
#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。
除了转换类型之外,还应该注意字符串的实际格式。
当编译多字节字符集Visual Studio和Win API时,假设UTF8(实际上是windows编码,即windows -28591)。
当为Unicode字符集Visual studio和Win API编译时,假设UTF16。
因此,您必须将字符串从UTF16转换为UTF8格式,而不仅仅是转换为std::string。
当使用多字符格式(如一些非拉丁语言)时,这将是必要的。
其思想是确定std::wstring总是表示UTF16。
std::string总是表示UTF8。
这不是由编译器强制执行的,这是一个更好的策略。
注意我用来定义UTF16 (L)和UTF8 (u8)的字符串前缀。
要在两种类型之间进行转换,您应该使用:std::codecvt_utf8_utf16< wchar_t>
#include <string>
#include <codecvt>
int main()
{
std::string original8 = u8"הלו";
std::wstring original16 = L"הלו";
//C++11 format converter
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
//convert to UTF8 and std::string
std::string utf8NativeString = convert.to_bytes(original16);
std::wstring utf16NativeString = convert.from_bytes(original8);
assert(utf8NativeString == original8);
assert(utf16NativeString == original16);
return 0;
}
来自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;
更新(2021年):但是,至少在MSVC的最新版本上,这可能会生成wchar_t到char截断警告。警告可以通过使用std::transform代替转换函数中的显式转换来消除,例如:
std::wstring wide( L"Wide" );
std::string str;
std::transform(wide.begin(), wide.end(), std::back_inserter(str), [] (wchar_t c) {
return (char)c;
});
或者如果你喜欢预分配而不使用back_inserter:
std::string str(wide.length(), 0);
std::transform(wide.begin(), wide.end(), str.begin(), [] (wchar_t c) {
return (char)c;
});
参见这里各种编译器的示例。
注意,这里根本没有进行字符集转换。它所做的只是将每个迭代的wchar_t赋值给一个char—截断转换。它使用std::string c'tor:
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
如评论所述:
值0-127在几乎所有编码中都是相同的,因此要截断
所有小于127的值都会生成相同的文本。输入一个
汉字,你会看到失败。
windows codepage 1252的值128-255 (windows English
默认值)和unicode的值128-255基本相同,因此如果
这就是你所使用的大部分字符的代码页
截断为正确的值。(我完全期待á和õ能正常工作,
我知道我们的代码在工作中依赖于é,我将很快修复)
请注意,Win1252中0x80 - 0x9F范围内的代码点将无法工作。这包括€,,,,…
我相信官方的方法仍然是使用codecvt facet(您需要某种语言环境感知的转换),例如
resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);
或者类似的东西,我没有工作代码。但我不确定现在有多少人使用这种机器,有多少人只是要求内存指针,让ICU或其他库处理血腥的细节。
下面是一个基于其他建议的解决方案:
#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上产生问题。