问题是如何将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。
这个解决方案的灵感来自dk123的解决方案,但是使用了一个依赖于地区的codecvt facet。结果是区域编码的字符串而不是UTF-8(如果它没有设置为区域设置):
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使用std::use_facet()函数与正确的typename获得正确的facet。希望这能有所帮助。
我花了很多悲伤的日子,试图为c++ 17找到一种方法来做到这一点,它已经弃用了code_cvt facet,这是我通过组合来自几个不同来源的代码所能想到的最好的方法:
setlocale( LC_ALL, "en_US.UTF-8" ); //Invoked in main()
std::string wideToMultiByte( std::wstring const & wideString )
{
std::string ret;
std::string buff( MB_CUR_MAX, '\0' );
for ( wchar_t const & wc : wideString )
{
int mbCharLen = std::wctomb( &buff[ 0 ], wc );
if ( mbCharLen < 1 ) { break; }
for ( int i = 0; i < mbCharLen; ++i )
{
ret += buff[ i ];
}
}
return ret;
}
std::wstring multiByteToWide( std::string const & multiByteString )
{
std::wstring ws( multiByteString.size(), L' ' );
ws.resize(
std::mbstowcs( &ws[ 0 ],
multiByteString.c_str(),
multiByteString.size() ) );
return ws;
}
我在Windows 10上测试了这段代码,至少就我的目的而言,它似乎运行良好。如果这没有考虑到你可能需要处理的一些疯狂的边缘情况,请不要对我进行私刑,我相信有更多经验的人可以改进这一点!: -)
此外,在该表扬的地方表扬:
适用于wideToMultiByte()
复制multiByteToWide
正如Cubbi在一条评论中指出的那样,std::wstring_convert (c++ 11)提供了一个简洁的解决方案(你需要#include <locale>和<codecvt>):
std::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的评论)
std::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);
}
std::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