问题是如何将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
但不仅仅是:
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转换为字符串。
答案 0 :(得分:268)
正如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日)强>
一个衬垫可以这样说(感谢Guss的评论):
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,则需要将其更改为您正在使用的相应编码:
答案 1 :(得分:117)
解决方案来自: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;
谨防此处有 no 字符集转换。这样做只是将每个迭代的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
范围内的代码点不有效。其中包括€
,œ
,ž
,Ÿ
,...
答案 2 :(得分:29)
以下是基于其他建议的解决方案:
#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上产生问题。
答案 3 :(得分:11)
除了包含区域设置和所有那些花哨的东西,如果你知道FACT你的字符串是可转换的,只需这样做:
#include <iostream>
#include <string>
using namespace std;
int main()
{
wstring w(L"bla");
string result;
for(char x : w)
result += x;
cout << result << '\n';
}
实例here
答案 4 :(得分:7)
我认为官方方式仍然是codecvt
方面(你需要某种语言环境感知翻译),如
resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);
或类似的东西,我没有工作代码。但我不确定现在有多少人使用这种机器,有多少人只是要求指向内存,让ICU或其他一些图书馆处理血腥细节。
答案 5 :(得分:6)
代码有两个问题:
const std::string s( ws.begin(), ws.end() );
中的转换不需要将宽字符正确映射到它们的窄对应字符。最有可能的是,每个宽字符只会被char
强制转换
此问题的解决方案已在the answer by kem中提供,并涉及区域设置narrow
方面的ctype
功能。
您正在同一程序中将输出写入std::cout
和std::wcout
。 cout
和wcout
都与相同的流(stdout
)相关联,并且使用相同的流作为面向字节的流(如cout
所做的那样)和未定义面向广泛的流(如wcout
所示)
最好的选择是避免将窄输出和宽输出混合到同一(底层)流。对于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;
}
答案 6 :(得分:6)
在撰写此答案时,谷歌搜索“convert string wstring”的第一名将会让您登陆此页面。我的回答显示了如何将字符串转换为wstring,虽然这不是实际的问题,我应该删除这个答案,但这被认为是不好的形式。你可能想要跳转到this StackOverflow answer,这是现在排名高于此页面。
这是将字符串,wstring和混合字符串常量组合到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();
答案 7 :(得分:6)
你也可以直接使用ctype facet的narrow方法:
#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]); }
答案 8 :(得分:3)
在我的情况下,我必须使用多字节字符(MBCS),我想使用std :: string和std :: wstring。并且不能使用c ++ 11。所以我使用mbstowcs和wcstombs。
我使用new,delete []做同样的功能,但它比这慢。
这可以帮助How to: Convert Between Various String Types
修改强>
但是,如果转换为wstring并且源字符串不是字母和多字节字符串,则它不起作用。 所以我将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);
}
答案 9 :(得分:3)
此解决方案受到dk123解决方案的启发,但使用依赖于语言环境的codecvt方面。结果是在locale编码的字符串而不是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);
}
我在寻找它,但我无法找到它。最后我发现我可以使用带有正确typename的std :: use_facet()函数从std :: locale获得正确的方面。希望这会有所帮助。
答案 10 :(得分:3)
除了转换类型之外,您还应该注意字符串的实际格式。
在编译多字节字符集时,Visual Studio和Win API假定使用UTF8(实际上是Windows-28591的Windows编码)。
在编译 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;
}
答案 11 :(得分:2)
默认编码为:
- Windows UTF-16。
- Linux UTF-8。
- MacOS UTF-8。
此代码具有两种形式,可将std :: string转换为std :: wstring,将std :: wstring转换为std :: string。 如果否定#if定义WIN32,则会得到相同的结果。
1。 std :: string到std :: wstring
•MultiByteToWideChar WinAPI
#if defined WIN32
#include <windows.h>
#endif
std::wstring StringToWideString(std::string str)
{
if (str.empty())
{
return std::wstring();
}
size_t len = str.length() + 1;
std::wstring ret = std::wstring(len, 0);
#if defined WIN32
int size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &str[0], str.size(), &ret[0], len);
ret.resize(size);
#else
size_t size = 0;
_locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
errno_t retval = _mbstowcs_s_l(&size, &ret[0], len, &str[0], _TRUNCATE, lc);
_free_locale(lc);
ret.resize(size - 1);
#endif
return ret;
}
2。 std :: wstring到std :: string
•WideCharToMultiByte WinAPI
std::string WidestringToString(std::wstring wstr)
{
if (wstr.empty())
{
return std::string();
}
#if defined WIN32
int size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), NULL, 0, NULL, NULL);
std::string ret = std::string(size, 0);
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &wstr[0], wstr.size(), &ret[0], size, NULL, NULL);
#else
size_t size = 0;
_locale_t lc = _create_locale(LC_ALL, "en_US.UTF-8");
errno_t err = _wcstombs_s_l(&size, NULL, 0, &wstr[0], _TRUNCATE, lc);
std::string ret = std::string(size, 0);
err = _wcstombs_s_l(&size, &ret[0], size, &wstr[0], _TRUNCATE, lc);
_free_locale(lc);
ret.resize(size - 1);
#endif
return ret;
}
3。在Windows上,您需要使用WinAPI打印unicode。
#if defined _WIN32
void WriteLineUnicode(std::string s)
{
std::wstring unicode = StringToWideString(s);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
std::cout << std::endl;
}
void WriteUnicode(std::string s)
{
std::wstring unicode = StringToWideString(s);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), unicode.length(), NULL, NULL);
}
void WriteLineUnicode(std::wstring ws)
{
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
std::cout << std::endl;
}
void WriteUnicode(std::wstring ws)
{
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), ws.c_str(), ws.length(), NULL, NULL);
}
4。在主程序上。
#if defined _WIN32
int wmain(int argc, WCHAR ** args)
#else
int main(int argc, CHAR ** args)
#endif
{
std::string source = u8"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča";
std::wstring wsource = L"ÜüΩωЙ你月曜日\naèéøÞǽлљΣæča";
WriteLineUnicode(L"@" + StringToWideString(source) + L"@");
WriteLineUnicode("@" + WidestringToString(wsource) + "@");
return EXIT_SUCCESS;
}
5。最后,您需要在控制台中对Unicode字符提供强大而完整的支持。 我推荐ConEmu并设置为default terminal on Windows。您需要将Visual Studio挂接到ConEmu。请记住,Visual Studio的exe文件是 devenv.exe
在带有VC ++的Visual Studio 2017上测试; std = c ++ 17。
结果
答案 12 :(得分:1)
如果其他人感兴趣:我需要一个可以互换使用的课程,无论是string
还是wstring
。基于dk123's solution的以下课程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_;
};
答案 13 :(得分:1)
我度过了很多悲伤的日子,试图提出一种针对C ++ 17的方法,该方法已弃用code_cvt
方面,这是我能够通过组合来自几个不同的来源:
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上测试了此代码,至少出于我的目的,它似乎工作正常。如果这不考虑您可能需要处理的一些疯狂案例,请不要私自给我,我敢肯定,有更多经验的人可以在此方面做得更好! :-)
此外,还应付款:
答案 14 :(得分:0)
如果您正在处理文件路径(就像我发现需要 wstring-to-string 时经常遇到的那样),您可以使用 filesystem::path(C++17 起):
#include <filesystem>
const std::wstring wPath = GetPath(); // some function that returns wstring
const std::string path = std::filesystem::path(wPath).string();
答案 15 :(得分:0)
#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); }
答案 16 :(得分:-1)
我在下面使用将wstring转换为字符串。
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;
答案 17 :(得分:-3)
// 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"