如何将std::stringstream转换为std::wstring

3

我的问题是如何将C++中的stringstream转换为wstringwstringstream

stringstream fileSearch;
fileSearch<<fileOutput.str();
fileSearch<<"*.jpg";
cout<<fileSearch.str()<<endl;

这是我的代码。我想将fileSearch stringstream转换为wstring... 有人能帮我吗?请提供c++示例代码... 我想在代码中使用这个filesearch stringstream。

int numOfFiles(wstring searchPath);

this function...


4
std::wstringstream - user2486888
2
简化后的问题是如何将std::string转换为std::wstring。这取决于所使用的编码方式,因此在某种程度上也取决于平台。 - Cheers and hth. - Alf
1
可能是重复的问题:如何将wstring转换为string? - Jonathan Potter
2
@close-voters:建议的重复问题是关于相反的转换(并且没有完整的答案)。 - Cheers and hth. - Alf
@qaisar:抱歉花了一些时间才搞定。我错误地认为ctype::widen可以完成任务。但是它在多字节编码中失败了(它只是无法使用的愚蠢函数),所以现在使用mbcstowcs - Cheers and hth. - Alf
std::char_traits 的怪癖 #328:widen 中的 n 代表“窄”。 - Potatoswatter
4个回答

6
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编码时。实际上,这意味着这种简单的数据复制方案适用于以下情况:
  • 在Windows西方安装中的Latin-1,因为Latin-1是Windows ANSI Western的子集。

  • 在其他Windows安装和Unix环境中的ASCII,因为默认系统窄编码通常不是Latin-1的扩展。


当窄字符串编码点不是宽字符串编码点的子集时,必须采用更积极的转换方式。
以下内容适用于std::string的编码为区域设置的窄文本编码,并且不包含嵌入的零字节:
#include <iostream>
#include <locale>       // std::locale
#include <locale.h>     // setlocale
#include <stdexcept>    // std::runtime_error
#include <stdlib.h>     // mbstowcs
#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++ 区域设置已设置为用户的默认区域设置。


2
在C++11中,您也可以使用以下代码将stringstream转换为wstring:
std::wstring stringStream2wstring(std::stringstream& strs)
{
    std::string str = strs.str();
    typedef std::codecvt_utf8<wchar_t> convert_type;
    std::wstring_convert<convert_type, wchar_t> converter;
    return converter.from_bytes(str);
}

注意:该示例使用std::codecvt_utf8


似乎已经过时。 - jrh

1
#include <boost\lexical_cast.hpp>
stringstream ss;    
std::wstring convertedStr = boost::lexical_cast<std::wstring>(ss);

请添加代码说明,这将极大地提高答案的质量。 - Nic3500

1
一个简短而简单的C++函数,用于将stringstream转换为wstring:
std::wstring convertToWString(std::stringstream& from)
{
    std::wstring to;
    string stdString = from.str();
    return to.assign(stdString.begin(), stdString.end());
}

注意:此代码仅限于ASCII字符集的值。

首先,您不能复制 std::stringstream。其次,没有这样的重载(您正在混淆 std::vector::assign)。第三,即使有这样的重载,它也无法处理 ASCII 以外的字符。 - edmz
除了“black”指出的问题外,(1)beginend是C++中的函数,而不是属性,(2)两个连续的str()调用引用不同的临时对象。 - Cheers and hth. - Alf
1
@Cheersandhth.-Alf,感谢您的评论,我添加了'&'和'()',运行代码后它现在按预期工作。 - Merav Kochavi
0已删除踩因为问题已解决。@MeravKochavi:请注意,这个方法的有效性取决于基于“char”的文本编码方式。使用UTF-8时,它仅限于ASCII值的子集(例如,挪威语的'Å'将失败)。使用Windows 1252时,它仅限于ISO Latin-1子集(例如,欧元符号'€'将失败)。问题在于stringstream不携带有关其编码的信息。但是,它携带了许多其他无关的信息。 - Cheers and hth. - Alf
@Cheersandhth.-Alf,我已经将你对ASCII限制的评论添加到答案中。 - Merav Kochavi
1
@MeravKochavi,既然你已经明确纠正了这个错误并提供了解决方案,让我们把这个问题擦掉吧。感谢你采取了纠正措施并添加了注释。 - Damian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接