问题是如何将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。


当前回答

我相信官方的方法仍然是使用codecvt facet(您需要某种语言环境感知的转换),例如

resultCode = use_facet<codecvt<char, wchar_t, ConversionState> >(locale).
  in(stateVar, scratchbuffer, scratchbufferEnd, from, to, toLimit, curPtr);

或者类似的东西,我没有工作代码。但我不确定现在有多少人使用这种机器,有多少人只是要求内存指针,让ICU或其他库处理血腥的细节。

其他回答

在写这个答案的时候,第一个谷歌搜索“转换字符串wstring”会让你进入这个页面。我的回答展示了如何将字符串转换为wstring,虽然这不是实际的问题,我应该删除这个答案,但这被认为是糟糕的形式。您可能希望跳转到此StackOverflow答案,该答案现在的排名高于此页面。


这是一种将字符串,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();

正如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

除了转换类型之外,还应该注意字符串的实际格式。

当编译多字节字符集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;
}

我使用下面的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;

如果你正在处理文件路径(当我发现需要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();