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


当前回答

代码有两个问题:

The conversion in const std::string s( ws.begin(), ws.end() ); is not required to correctly map the wide characters to their narrow counterpart. Most likely, each wide character will just be typecast to char. The resolution to this problem is already given in the answer by kem and involves the narrow function of the locale's ctype facet. You are writing output to both std::cout and std::wcout in the same program. Both cout and wcout are associated with the same stream (stdout) and the results of using the same stream both as a byte-oriented stream (as cout does) and a wide-oriented stream (as wcout does) are not defined. The best option is to avoid mixing narrow and wide output to the same (underlying) stream. For stdout/cout/wcout, you can try switching the orientation of stdout when switching between wide and narrow output (or vice versa): #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; }

其他回答

来自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;

更新(2021年):但是,至少在MSVC的最新版本上,这可能会生成wchar_t到char截断警告。警告可以通过使用std::transform代替转换函数中的显式转换来消除,例如:

std::wstring wide( L"Wide" );

std::string str;
std::transform(wide.begin(), wide.end(), std::back_inserter(str), [] (wchar_t c) {
    return (char)c;
});

或者如果你喜欢预分配而不使用back_inserter:

std::string str(wide.length(), 0);
std::transform(wide.begin(), wide.end(), str.begin(), [] (wchar_t c) {
    return (char)c;
});

参见这里各种编译器的示例。


注意,这里根本没有进行字符集转换。它所做的只是将每个迭代的wchar_t赋值给一个char—截断转换。它使用std::string c'tor:

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

如评论所述:

值0-127在几乎所有编码中都是相同的,因此要截断 所有小于127的值都会生成相同的文本。输入一个 汉字,你会看到失败。

windows codepage 1252的值128-255 (windows English 默认值)和unicode的值128-255基本相同,因此如果 这就是你所使用的大部分字符的代码页 截断为正确的值。(我完全期待á和õ能正常工作, 我知道我们的代码在工作中依赖于é,我将很快修复)

请注意,Win1252中0x80 - 0x9F范围内的代码点将无法工作。这包括€,,,,…

你也可以直接使用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]);
}

如果其他人感兴趣的话:我需要一个可以在任何期望使用string或wstring的地方互换使用的类。下面的类convertible_string,基于dk123的解决方案,可以用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_;
};

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

// 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"