std::stringstream
可以随时转换为
std::string
,因此问题简化为如何将
std::string
转换为
std::wstring
。
如果窄字符串编码点是宽字符串编码点的子集,则可以直接复制数据。
const std::string s = ...;
const std::wstring ws( s.begin(), s.end() );
这适用于原始ASCII及其扩展Latin-1,当宽字符串为UTF-16或UTF-32编码时。实际上,这意味着这种简单的数据复制方案适用于以下情况:
当窄字符串编码点不是宽字符串编码点的子集时,必须采用更积极的转换方式。
以下内容适用于
std::string
的编码为区域设置的窄文本编码,并且不包含嵌入的零字节:
#include <iostream>
#include <locale>
#include <locale.h>
#include <stdexcept>
#include <stdlib.h>
#include <string>
using namespace std;
auto hopefully( const bool condition ) -> bool { return condition; }
auto fail( const string& message ) -> bool { throw runtime_error( message ); }
auto widened( const string& s, locale const& loc = locale() )
-> wstring
{
const int n = s.length();
if( n == 0 ) { return L""; }
const int max_wide_encoding_values = (sizeof( wchar_t ) == 2? 2 : 1);
wstring ws( max_wide_encoding_values*s.length(), L'\0' );
const auto n_characters_stored = mbstowcs( &ws[0], &s[0], ws.size() );
hopefully( n_characters_stored != -1 )
|| fail( "mbstowcs failed" );
ws.resize( n_characters_stored );
return ws;
}
auto operator<<( wostream& stream, const string& s )
-> wostream&
{ return stream << s.c_str(); }
auto main() -> int
{
setlocale( LC_ALL, "" );
locale::global( locale( "" ) );
const wstring ws = widened( "Blåbærsyltetøy." );
for( const wchar_t wc : ws )
{
wcout << int( wc ) << ' ';
}
wcout << endl;
wcout << L"Should be 'Blåbærsyltetøy'." << endl;
wcout << L"Is '" << ws << L"'." << endl;
}
在Windows中,需要添加一些修复程序以使宽流输出正常工作:
C:\Users\alf\dev\explore\_\so\0244> g++ foo.cpp -std=c++11
C:\Users\alf\dev\explore\_\so\0244> a.exe
66 108 195 165 98 195 166 114 115 121 108 116 101 116 195 184 121 46
Should be 'Blåbærsyltetøy'.
Is 'Blåbærsyltetøy'.
C:\Users\alf\dev\explore\_\so\0244> ▯
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
static const bool _ = []() -> bool
{
const int fd = _fileno( stdout );
_setmode( fd, _isatty( fd )? _O_WTEXT : _O_U8TEXT );
return true;
}();
在 Windows 上,使用 Visual C++ 的输出结果为:
H:\dev\explore\_\so\0244>cl iofix.cpp foo.cpp /Feb
iofix.cpp
foo.cpp
Generating Code...
H:\dev\explore\_\so\0244>b
66 108 229 98 230 114 115 121 108 116 101 116 248 121 46
应该是 'Blåbærsyltetøy'。
是 'Blåbærsyltetøy'。
H:\dev\explore\_\so\0244>_
然而,在 Windows 中使用 MinGW g++ 时,默认输出结果不正确:
H:\dev\explore\_\so\0244>g++ iofix.cpp foo.cpp
H:\dev\explore\_\so\0244>a
66 108 195 165 98 195 166 114 115 121 108 116 101 116 195 184 121 46
应该是 'Blåbærsyltetøy'。
是 'BlÃ¥bærsyltetøy'。
H:\dev\explore\_\so\0244>_
其原因是默认的 g++ 的 C++ 执行字符集为 UTF-8,而这不是 Windows 默认用户区域设置指定的窄文本编码。一个简单的解决方法是为 g++ 指定正确的执行字符集。然而,只有支持这些选项的 g++ 发行版才能实现这一点,例如 Nuwen 发行版就不支持。
1) 在 Unix 中,它可以正常工作,因为全局 C++ 区域设置已设置为用户的默认区域设置。
std::wstringstream
- user2486888std::string
转换为std::wstring
。这取决于所使用的编码方式,因此在某种程度上也取决于平台。 - Cheers and hth. - Alfctype::widen
可以完成任务。但是它在多字节编码中失败了(它只是无法使用的愚蠢函数),所以现在使用mbcstowcs
。 - Cheers and hth. - Alfwiden
中的n
代表“窄”。 - Potatoswatter