Output unicode strings in Windows console app

后端 未结 11 957
花落未央
花落未央 2020-11-21 11:20

Hi I was trying to output unicode string to a console with iostreams and failed.

I found this: Using unicode font in c++ console app and this snippet work

11条回答
  •  情歌与酒
    2020-11-21 12:09

    Default encoding on:

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

    My solution Steps, includes null chars \0 (avoid truncated). Without using functions on windows.h header:

    1. Add Macros to detect Platform.
    #if defined (_WIN32) 
    #define WINDOWSLIB 1
    
    #elif defined (__ANDROID__) || defined(ANDROID)//Android
    #define ANDROIDLIB 1
    
    #elif defined (__APPLE__)//iOS, Mac OS
    #define MACOSLIB 1
    
    #elif defined (__LINUX__) || defined(__gnu_linux__) || defined(__linux__)//_Ubuntu - Fedora - Centos - RedHat
    #define LINUXLIB 1
    #endif
    
    1. Create conversion functions std::wstring to std::string or viceversa.
    #include 
    #include 
    #include 
    #ifdef WINDOWSLIB
    #include 
    #endif
    
    using namespace std::literals::string_literals;
    
    // Convert std::wstring to std::string
    std::string WidestringToString(const std::wstring& wstr, const std::string& locale)
    {
        if (wstr.empty())
        {
            return std::string();
        }
        size_t pos;
        size_t begin = 0;
        std::string ret;
        size_t  size;
    #ifdef WINDOWSLIB
        _locale_t lc = _create_locale(LC_ALL, locale.c_str());
        pos = wstr.find(static_cast(0), begin);
        while (pos != std::wstring::npos && begin < wstr.length())
        {
            std::wstring segment = std::wstring(&wstr[begin], pos - begin);
            _wcstombs_s_l(&size, nullptr, 0, &segment[0], _TRUNCATE, lc);
            std::string converted = std::string(size, 0);
            _wcstombs_s_l(&size, &converted[0], size, &segment[0], _TRUNCATE, lc);
            ret.append(converted);
            begin = pos + 1;
            pos = wstr.find(static_cast(0), begin);
        }
        if (begin <= wstr.length()) {
            std::wstring segment = std::wstring(&wstr[begin], wstr.length() - begin);
            _wcstombs_s_l(&size, nullptr, 0, &segment[0], _TRUNCATE, lc);
            std::string converted = std::string(size, 0);
            _wcstombs_s_l(&size, &converted[0], size, &segment[0], _TRUNCATE, lc);
            converted.resize(size - 1);
            ret.append(converted);
        }
        _free_locale(lc);
    #elif defined LINUXLIB
        std::string currentLocale = setlocale(LC_ALL, nullptr);
        setlocale(LC_ALL, locale.c_str());
        pos = wstr.find(static_cast(0), begin);
        while (pos != std::wstring::npos && begin < wstr.length())
        {
            std::wstring segment = std::wstring(&wstr[begin], pos - begin);
            size = wcstombs(nullptr, segment.c_str(), 0);
            std::string converted = std::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(0), begin);
        }
        if (begin <= wstr.length()) {
            std::wstring segment = std::wstring(&wstr[begin], wstr.length() - begin);
            size = wcstombs(nullptr, segment.c_str(), 0);
            std::string converted = std::string(size, 0);
            wcstombs(&converted[0], segment.c_str(), converted.size());
            ret.append(converted);
        }
        setlocale(LC_ALL, currentLocale.c_str());
    #elif defined MACOSLIB
    #endif
    
        return ret;
    }
    
    // Convert std::string to std::wstring
    std::wstring StringToWideString(const std::string& str, const std::string& locale)
    {
        if (str.empty())
        {
            return std::wstring();
        }
    
        size_t pos;
        size_t begin = 0;
        std::wstring ret;
        size_t  size;
    
    #ifdef WINDOWSLIB
        _locale_t lc = _create_locale(LC_ALL, locale.c_str());
        pos = str.find(static_cast(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);
            _mbstowcs_s_l(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE, lc);
            converted.resize(size - 1);
            ret.append(converted);
            ret.append({ 0 });
            begin = pos + 1;
            pos = str.find(static_cast(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);
            _mbstowcs_s_l(&size, &converted[0], converted.size(), &segment[0], _TRUNCATE, lc);
            converted.resize(size - 1);
            ret.append(converted);
        }
        _free_locale(lc);
    #elif defined LINUXLIB
        std::string currentLocale = setlocale(LC_ALL, nullptr);
        setlocale(LC_ALL, locale.c_str());
        pos = str.find(static_cast(0), begin);
        while (pos != std::string::npos) {
            std::string segment = std::string(&str[begin], pos - begin);
            std::wstring converted = std::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(0), begin);
        }
        if (begin < str.length()) {
            std::string segment = std::string(&str[begin], str.length() - begin);
            std::wstring converted = std::wstring(segment.size(), 0);
            size = mbstowcs(&converted[0], &segment[0], converted.size());
            converted.resize(size);
            ret.append(converted);
        }
        setlocale(LC_ALL, currentLocale.c_str());
    #elif defined MACOSLIB
    #endif
    
        return ret;
    }
    
    1. Print std::string. Check RawString Suffix.

    Linux Code. Print directly std::string using std::cout.
    If you have std::wstring.
    1. Convert to std::string.
    2. Print with std::cout.

    std::wstring x = L"\0\001日本ABC\0DE\0F\0G

提交回复
热议问题