如何将wstring转换为字符串?

BЈо*_*вић 191 c++ unicode stl wstring

问题是如何将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;
}
Run Code Online (Sandbox Code Playgroud)

注释掉的输出是:

std::string =     Hello
std::wstring =    Hello
std::string =     Hello
Run Code Online (Sandbox Code Playgroud)

但不仅仅是:

std::wstring =    Hello
Run Code Online (Sandbox Code Playgroud)

这个例子有什么不对吗?我可以像上面那样进行转换吗?

编辑

新的例子(考虑到一些答案)是

#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;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

std::string =     Hello
std::wstring =    Hello
std::stringstream =     0x860283c
Run Code Online (Sandbox Code Playgroud)

因此stringstream不能用于将wstring转换为字符串.

dk1*_*123 296

正如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 );
Run Code Online (Sandbox Code Playgroud)

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");
Run Code Online (Sandbox Code Playgroud)

包装函数可以这样说:(感谢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);
}
Run Code Online (Sandbox Code Playgroud)

注意:关于是否string/ wstring应该作为引用或文字传递给函数存在一些争议(由于C++ 11和编译器更新).我会把决定留给实施者,但值得了解.

注意:我std::codecvt_utf8在上面的代码中使用,但如果您不使用UTF-8,则需要将其更改为您正在使用的相应编码:

http://en.cppreference.com/w/cpp/header/codecvt

  • *请+ 1*:这是进行字符串转换的官方C++标准方法.您也可以使用from_bytes转换其他方式.因为我个人喜欢单行,这是我的版本:`std :: wstring str = std :: wstring_convert <std :: codecvt_utf <wchar_t >>().from_bytes("some string");` (24认同)
  • 从g ++ 4.8.2开始,似乎没有http://en.cppreference.com/w/cpp/header/codecvt.两个s2ws和ws2s方法目前不能在linux下运行 (7认同)
  • 看起来这已被弃用(/sf/answers/3006258951/).当我尝试运行此代码时,我的编译器会抛出错误 (4认同)
  • 在C ++ 17上已弃用... https://en.cppreference.com/w/cpp/locale/wstring_convert https://en.cppreference.com/w/cpp/locale/codecvt_utf8 (3认同)
  • 对于担心C ++ 17和进一步兼容性(由于弃用)的任何人,请参见:/sf/answers/1301816911/ (3认同)
  • 在我遇到这个问题之前,我花了两个星期的时间使用巨大的狡猾模板怪物.**谢谢**.请考虑在一个简单的`std :: string ws2s(std :: wstring const&)`函数中包装,可能会以这种方式获得更多的投票. (2认同)

nam*_*309 123

解决方案来自: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;
Run Code Online (Sandbox Code Playgroud)

请注意,这里根本没有进行字符集转换.这样做是简单地分配给每个迭代wchar_tchar-一截断转换.它使用std :: string c'tor:

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)

如评论中所述:

几乎每个编码中的值0-127都是相同的,因此截断小于127的值会产生相同的文本.放入一个汉字,你会看到失败.

-

Windows代码页1252(Windows英文默认值)的值128-255和unicode的值128-255大致相同,因此如果您使用的那些代码页中的大部分字符应该被截断为正确的值.(我完全希望á和õ能够工作,我知道我们的工作代码依赖于é,我很快就会解决这个问题)

并注意范围的代码点0x80 - 0x9FWin1252无法正常工作.这包括,œ,ž,Ÿ,...

  • @PedroLamarão:值0-127几乎在每个编码中都相同,因此截断小于127的值会产生相同的文本.放入一个汉字,你会看到失败. (7认同)
  • ...当它涉及任何非拉丁字符. (3认同)
  • @PedroLamarão:Windows代码页1252(Windows英文默认值)的值128-255和unicode的值128-255几乎相同,所以如果那个代码页你正在使用这些字符中的大部分应截断为正确值.(我完全希望á和õ能够工作,我知道我们的工作代码依赖于é,我很快就会解决这个问题) (3认同)
  • 奇怪的是,这在Visual Studio 10上有效。发生了什么?对于原始字符串的所有元素,这将导致从wchar_t到char的截断分配。 (2认同)

Phi*_*ipp 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

这通常适用于Linux,但会在Windows上产生问题.

  • 来自C++ 11的`std :: wstring_convert`包含了很多这种噪音. (30认同)
  • @Philipp,你的意思是"会在Windows上造成问题"吗?什么样的问题? (5认同)
  • 使用`std :: wcout.imbue(locale)`也可以完成这项工作,它的好处是它不会改变任何全局状态. (2认同)
  • 上面的代码(如复制的)给我一个“*** glibc检测到***测试:malloc():smallbin双链表损坏:0x000000000180ea30 ***”在linux 64位(gcc 4.7.3)上。还有其他人遇到过这种情况吗? (2认同)

小智 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';
}
Run Code Online (Sandbox Code Playgroud)

这里有实例

  • -1如果你有一个wstring,你可能正在处理多字节字符.如果你知道字符串是可以轻易转换的,那么你首先不会处理一个wstring.更有可能的是,您正在处理另一个希望您正确处理wstring的库.截断wchars只是在以后乞求难以追踪的bug.此外,你应该使用"字符串结果(w.begin(),w.end());" 如果您打算这样做,以避免可能触发许多重新分配的循环. (9认同)
  • +1因为它是一个适用于某些场景的简单解决方案(对于"作品"的松散定义,我可能会添加). (2认同)
  • 几乎与namar0x0309的解决方案相同,这是更优雅的恕我直言.但那只是我. (2认同)

Jom*_*oma 11

默认编码:

  • Windows UTF-16。
  • Linux UTF-8。
  • MacOS UTF-8。

我的解决方案步骤,包括空字符 \0 (避免被截断)。不使用 windows.h 头文件上的函数:

  1. 添加宏来检测平台。 Windows/Linux 和其他
  1. 创建将 std::wstring 转换为 std::string 并将 std::string 反转为 std::wstring 的函数
  1. 创建打印功能
  1. 打印 std::string/ std::wstring

检查RawString 文字。原始字符串后缀。

Linux 代码。使用std::cout直接打印std::string,Linux 上的默认编码是 UTF-8,不需要额外的功能。

在 Windows 上,如果您需要打印 unicode。我们可以使用WriteConsole从 std::wstring 打印 unicode 字符。

最后在 Windows 上。您需要在控制台中为 unicode 字符提供强大而完整的视图支持。 我推荐Windows 终端

质量保证

  • 使用 VC++ 在 Microsoft Visual Studio 2019 上测试;标准=c++17。(Windows 项目)
  • 使用 Clang 编译器在 repl.it 上进行测试;标准=c++17。

问:为什么不使用<codecvt>头函数和类?
A.弃用 删除或弃用的功能不可能在 VC++ 上构建,但在 g++ 上没有问题。我更喜欢 0 警告和头痛。

问: std ::wstring 是跨平台的吗?
A.否。 std::wstring 使用 wchar_t 元素。在 Windows 上 wchar_t 大小为 2 个字节,每个字符以 UTF-16 单元存储,如果字符大于 U+FFFF,则字符以两个 UTF-16 单元(2 个 wchar_t 元素)表示,称为代理对。在 Linux 上 wchar_t 大小是 4 个字节,每个字符存储在一个 wchar_t 元素中,不需要代理对。检查UNIX、Linux 和 Windowsl 上的标准数据类型

问: std ::string 是跨平台的吗?
答:是的。std::string 使用字符元素。在大多数编译器中保证 char 类型具有相同的字节大小。char 类型大小为 1 个字节。检查UNIX、Linux 和 Windowsl 上的标准数据类型

完整示例代码


#include <iostream>
#include <set>
#include <string>
#include <locale>

// WINDOWS
#if (_WIN32)
#include <Windows.h>
#include <conio.h>
#define WINDOWS_PLATFORM 1
#define DLLCALL STDCALL
#define DLLIMPORT _declspec(dllimport)
#define DLLEXPORT _declspec(dllexport)
#define DLLPRIVATE
#define NOMINMAX

//EMSCRIPTEN
#elif defined(__EMSCRIPTEN__)
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <unistd.h>
#include <termios.h>
#define EMSCRIPTEN_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))

// LINUX - Ubuntu, Fedora, , Centos, Debian, RedHat
#elif (__LINUX__ || __gnu_linux__ || __linux__ || __linux || linux)
#define LINUX_PLATFORM 1
#include <unistd.h>
#include <termios.h>
#define DLLCALL CDECL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#define CoTaskMemAlloc(p) malloc(p)
#define CoTaskMemFree(p) free(p)

//ANDROID
#elif (__ANDROID__ || ANDROID)
#define ANDROID_PLATFORM 1
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))

//MACOS
#elif defined(__APPLE__)
#include <unistd.h>
#include <termios.h>
#define DLLCALL
#define DLLIMPORT
#define DLLEXPORT __attribute__((visibility("default")))
#define DLLPRIVATE __attribute__((visibility("hidden")))
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
#define IOS_SIMULATOR_PLATFORM 1
#elif TARGET_OS_IPHONE
#define IOS_PLATFORM 1
#elif TARGET_OS_MAC
#define MACOS_PLATFORM 1
#else

#endif

#endif



typedef std::string String;
typedef std::wstring WString;

#define EMPTY_STRING u8""s
#define EMPTY_WSTRING L""s

using namespace std::literals::string_literals;

class Strings
{
public:
    static String WideStringToString(const WString& wstr)
    {
        if (wstr.empty())
        {
            return String();
        }
        size_t pos;
        size_t begin = 0;
        String ret;

#if WINDOWS_PLATFORM
        int size;
        pos = wstr.find(static_cast<wchar_t>(0), begin);
        while (pos != WString::npos && begin < wstr.length())
        {
            WString segment = WString(&wstr[begin], pos - begin);
            size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
            String converted = String(size, 0);
            WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
            ret.append(converted);
            ret.append({ 0 });
            begin = pos + 1;
            pos = wstr.find(static_cast<wchar_t>(0), begin);
        }
        if (begin <= wstr.length())
        {
            WString segment = WString(&wstr[begin], wstr.length() - begin);
            size = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), NULL, 0, NULL, NULL);
            String converted = String(size, 0);
            WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.size(), NULL, NULL);
            ret.append(converted);
        }
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
        size_t size;
        pos = wstr.find(static_cast<wchar_t>(0), begin);
        while (pos != WString::npos && begin < wstr.length())
        {
            WString segment = WString(&wstr[begin], pos - begin);
            size = wcstombs(nullptr, segment.c_str(), 0);
            String converted = String(size, 0);
            wcstombs(&converted[0], segment.c_str(), converted.size());
            ret.append(converted);
            ret.append({ 0 });
            begin = pos + 1;
            pos = wstr.find(static_cast<wchar_t>(0), begin);
        }
        if (begin <= wstr.length())
        {
            WString segment = WString(&wstr[begin], wstr.length() - begin);
            size = wcstombs(nullptr, segment.c_str(), 0);
            String converted = String(size, 0);
            wcstombs(&converted[0], segment.c_str(), converted.size());
            ret.append(converted);
        }
#else
        static_assert(false, "Unknown Platform");
#endif
        return ret;
    }

    static WString StringToWideString(const String& str)
    {
        if (str.empty())
        {
            return WString();
        }

        size_t pos;
        size_t begin = 0;
        WString ret;
#ifdef WINDOWS_PLATFORM
        int size = 0;
        pos = str.find(static_cast<char>(0), begin);
        while (pos != std::string::npos) {
            std::string segment = std::string(&str[begin], pos - begin);
            std::wstring converted = std::wstring(segment.size() + 1, 0);
            size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, &segment[0], segment.size(), &converted[0], converted.length());
            converted.resize(size);
            ret.append(converted);
            ret.append({ 0 });
            begin = pos + 1;
            pos = str.find(static_cast<char>(0), begin);
        }
        if (begin < str.length()) {
            std::string segment = std::string(&str[begin], str.length() - begin);
            std::wstring converted = std::wstring(segment.size() + 1, 0);
            size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, segment.c_str(), segment.size(), &converted[0], converted.length());
            converted.resize(size);
            ret.append(converted);
        }

#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
        size_t size;
        pos = str.find(static_cast<char>(0), begin);
        while (pos != String::npos)
        {
            String segment = String(&str[begin], pos - begin);
            WString converted = WString(segment.size(), 0);
            size = mbstowcs(&converted[0], &segment[0], converted.size());
            converted.resize(size);
            ret.append(converted);
            ret.append({ 0 });
            begin = pos + 1;
            pos = str.find(static_cast<char>(0), begin);
        }
        if (begin < str.length())
        {
            String segment = String(&str[begin], str.length() - begin);
            WString converted = WString(segment.size(), 0);
            size = mbstowcs(&converted[0], &segment[0], converted.size());
            converted.resize(size);
            ret.append(converted);
        }
#else
        static_assert(false, "Unknown Platform");
#endif
        return ret;
    }
};

enum class ConsoleTextStyle
{
    DEFAULT = 0,
    BOLD = 1,
    FAINT = 2,
    ITALIC = 3,
    UNDERLINE = 4,
    SLOW_BLINK = 5,
    RAPID_BLINK = 6,
    REVERSE = 7,
};

enum class ConsoleForeground
{
    DEFAULT = 39,
    BLACK = 30,
    DARK_RED = 31,
    DARK_GREEN = 32,
    DARK_YELLOW = 33,
    DARK_BLUE = 34,
    DARK_MAGENTA = 35,
    DARK_CYAN = 36,
    GRAY = 37,
    DARK_GRAY = 90,
    RED = 91,
    GREEN = 92,
    YELLOW = 93,
    BLUE = 94,
    MAGENTA = 95,
    CYAN = 96,
    WHITE = 97
};

enum class ConsoleBackground
{
    DEFAULT = 49,
    BLACK = 40,
    DARK_RED = 41,
    DARK_GREEN = 42,
    DARK_YELLOW = 43,
    DARK_BLUE = 44,
    DARK_MAGENTA = 45,
    DARK_CYAN = 46,
    GRAY = 47,
    DARK_GRAY = 100,
    RED = 101,
    GREEN = 102,
    YELLOW = 103,
    BLUE = 104,
    MAGENTA = 105,
    CYAN = 106,
    WHITE = 107
};

class Console
{
private:
    static void EnableVirtualTermimalProcessing()
    {
#if defined WINDOWS_PLATFORM
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        DWORD dwMode = 0;
        GetConsoleMode(hOut, &dwMode);
        if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
        {
            dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
            SetConsoleMode(hOut, dwMode);
        }
#endif
    }

    static void ResetTerminalFormat()
    {
        std::cout << u8"\033[0m";
    }

    static void SetVirtualTerminalFormat(ConsoleForeground foreground, ConsoleBackground background, std::set<ConsoleTextStyle> styles)
    {
        String format = u8"\033[";
        format.append(std::to_string(static_cast<int>(foreground)));
        format.append(u8";");
        format.append(std::to_string(static_cast<int>(background)));
        if (styles.size() > 0)
        {
            for (auto it = styles.begin(); it != styles.end(); ++it)
            {
                format.append(u8";");
                format.append(std::to_string(static_cast<int>(*it)));
            }
        }
        format.append(u8"m");
        std::cout << format;
    }
public:
    static void Clear()
    {

#ifdef WINDOWS_PLATFORM
        std::system(u8"cls");
#elif LINUX_PLATFORM || defined MACOS_PLATFORM
        std::system(u8"clear");
#elif EMSCRIPTEN_PLATFORM
        emscripten::val::global()["console"].call<void>(u8"clear");
#else
        static_assert(false, "Unknown Platform");
#endif
    }

    static void Write(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
    {
#ifndef EMSCRIPTEN_PLATFORM
        EnableVirtualTermimalProcessing();
        SetVirtualTerminalFormat(foreground, background, styles);
#endif
        String str = s;
#ifdef WINDOWS_PLATFORM
        WString unicode = Strings::StringToWideString(str);
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), unicode.c_str(), static_cast<DWORD>(unicode.length()), nullptr, nullptr);
#elif defined LINUX_PLATFORM || defined MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
        std::cout << str;
#else
        static_assert(false, "Unknown Platform");
#endif

#ifndef EMSCRIPTEN_PLATFORM
        ResetTerminalFormat();
#endif
    }

    static void WriteLine(const String& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
    {
        Write(s, foreground, background, styles);
        std::cout << std::endl;
    }

    static void Write(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
    {
#ifndef EMSCRIPTEN_PLATFORM
        EnableVirtualTermimalProcessing();
        SetVirtualTerminalFormat(foreground, background, styles);
#endif
        WString str = s;

#ifdef WINDOWS_PLATFORM
        WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), static_cast<DWORD>(str.length()), nullptr, nullptr);
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
        std::cout << Strings::WideStringToString(str);
#else
        static_assert(false, "Unknown Platform");
#endif

#ifndef EMSCRIPTEN_PLATFORM
        ResetTerminalFormat();
#endif
    }

    static void WriteLine(const WString& s, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
    {
        Write(s, foreground, background, styles);
        std::cout << std::endl;
    }

    static void WriteLine()
    {
        std::cout << std::endl;
    }

    static void Pause()
    {
        char c;
        do
        {
            c = getchar();
            std::cout << "Press Key " << std::endl;
        } while (c != 64);
        std::cout << "KeyPressed" << std::endl;
    }

    static int PauseAny(bool printWhenPressed = false, ConsoleForeground foreground = ConsoleForeground::DEFAULT, ConsoleBackground background = ConsoleBackground::DEFAULT, std::set<ConsoleTextStyle> styles = {})
    {
        int ch;
#ifdef WINDOWS_PLATFORM
        ch = _getch();
#elif LINUX_PLATFORM || MACOS_PLATFORM || EMSCRIPTEN_PLATFORM
        struct termios oldt, newt;
        tcgetattr(STDIN_FILENO, &oldt);
        newt = oldt;
        newt.c_lflag &= ~(ICANON | ECHO);
        tcsetattr(STDIN_FILENO, TCSANOW, &newt);
        ch = getchar();
        tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#else
        static_assert(false, "Unknown Platform");
#endif
        if (printWhenPressed)
        {
            Console::Write(String(1, ch), foreground, background, styles);
        }
        return ch;
    }
};



int main()
{
    std::locale::global(std::locale(u8"en_US.UTF8"));
    auto str = u8"\0Hello\0123456789????????????????????"s;//
    WString wstr = L"\0Hello\0123456789????????????????????"s;
    WString wstrResult = Strings::StringToWideString(str);
    String strResult = Strings::WideStringToString(wstr);
    bool equals1 = wstr == wstrResult;
    bool equals2 = str == strResult;

    Console::WriteLine(u8"? Converted Strings printed with Console::WriteLine"s, ConsoleForeground::GREEN);
    Console::WriteLine(wstrResult, ConsoleForeground::BLUE);//Printed OK on Windows/Linux.
    Console::WriteLine(strResult, ConsoleForeground::BLUE);//Printed OK on Windows/Linux.
    
    Console::WriteLine(u8"? Converted Strings printed with std::cout/std::wcout"s, ConsoleForeground::GREEN);
    std::cout << strResult << std::endl;//Printed OK on Linux. BAD on Windows.
    std::wcout << wstrResult << std::endl; //Printed BAD on Windows/Linux.
    Console::WriteLine();
    Console::WriteLine(u8"Press any key to exit"s, ConsoleForeground::DARK_GRAY);
    Console::PauseAny();

}
Run Code Online (Sandbox Code Playgroud)

您无法在https://repl.it/@JomaCorpFX/StringToWideStringToString#main.cpp上测试此代码


**截图**

使用 Windows 终端 视窗终端

使用 cmd/powershell 在此处输入图片说明

复制捕获
在此处输入图片说明


Chr*_*zig 7

我认为官方的方式仍然是深入研究codecvt(你需要某种类似于语言环境的翻译),如同

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

或类似的东西,我没有工作代码.但我不确定这些天有多少人使用这种机器,有多少人只是要求指向内存,让ICU或其他一些图书馆处理血腥细节.


Bar*_*nau 7

代码有两个问题:

  1. 转换输入const std::string s( ws.begin(), ws.end() );不需要将宽字符正确映射到它们的窄对应物.最有可能的是,每个广泛的角色都会被强制转换char.
    这个问题的解决方案已在kem的答案中给出,并涉及narrowlocale的ctypefacet 的功能.

  2. 您正在将输出写入两个程序std::coutstd::wcout在同一程序中.二者coutwcout用相同的流(相关联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;
    }
    
    Run Code Online (Sandbox Code Playgroud)


tim*_*ton 7

如果您正在处理文件路径(当我发现需要 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();
Run Code Online (Sandbox Code Playgroud)


leg*_*ize 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]);
}


Viz*_*zor 6

该解决方案受到dk123 解决方案的启发,但使用了依赖于语言环境的 codecvt 方面。结果是区域设置编码字符串而不是 UTF-8(如果未设置为区域设置):

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);
}
Run Code Online (Sandbox Code Playgroud)

我一直在寻找它,但我找不到它。最后我发现我可以通过std::locale使用std::use_facet()具有正确类型名的函数来获得正确的方面。希望这可以帮助。


LH1*_*395 6

我花了很多悲伤的日子试图想出一种方法来为 C++17 做到这一点,它已弃用code_cvtFacet,这是我通过组合来自几个不同来源的代码所能想到的最好的方法:

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;
 }
Run Code Online (Sandbox Code Playgroud)

我在 Windows 10 上测试了这段代码,至少就我的目的而言,它似乎工作得很好。如果这没有考虑到您可能需要处理的一些疯狂的边缘情况,请不要私刑处死我,我相信有更多经验的人可以对此进行改进!:-)

另外,贷记应得的:

适合wideToMultiByte()

复制为 multiByteToWide


Mar*_*ata 5

在撰写此答案时,排名第一的Google搜索"convert string 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();
Run Code Online (Sandbox Code Playgroud)

  • 这不是字符串转换的字符串 (13认同)

Yoc*_*mer 5

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

编译多字节字符集时, 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;
}
Run Code Online (Sandbox Code Playgroud)