How to output and input UTF8 or UTF16 Unicode text in Windows using C++?

Nik*_*kos 5 c++ windows winapi locale facet

This is my program:

#include <iostream>
#include <string>
#include <locale>
#include <clocale>
#include <codecvt>
#include <io.h>
#include <fcntl.h>

int main()
{
    fflush(stdout);
    _setmode(_fileno(stdout), _O_U16TEXT);
    std::ios_base::sync_with_stdio(false);
    std::setlocale(LC_ALL, "el_GR.utf8");
    std::locale loc{ "el_GR.utf8" };
    std::locale::global(loc);       // apparently this does not set the global locale
    //std::wcout.imbue(loc);
    //std::wcin.imbue(loc);

    std::wstring yes;
    std::wcout << L"It's all good ???? ???" << L'\n';
    std::wcin >> yes;
    std::wcout << yes << L'\n';
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Lets say I want to support greek encodings (for both input and output). This program works perfectly on Linux for various output and input languages if I set the appropriate encoding and of course remove the fflush(stdout) and _setmode().

So on Windows this program will output greek (and english) correctly when I use std::locale::global(loc), but It will not take greek input that I type from the keyboard. The std::wcout << yes outputs gibberish or question marks if I type greek. Apparently ::global isn't really global on Windows?

So I tried the .imbue() method on wcout and wcin (which also works on Linux) that you see commented out here. When I use any of these two statements and run the program it will (compile properly) present me with a prompt and when I press w/e and then press 'enter' it simply exits with no errors or whatnot.

I have tried a few Windows specific commands but then I got confused too. What should I try and when on Windows is not clear to me.

So the question is how I can both input and output greek text properly in Windows like in the program above? I use MSVS 2017 latest updates. Thanks in advance.

Nik*_*kos 0

正如 @Eryk Sun 在评论中提到的,我必须使用_setmode(_fileno(stdin), _O_U16TEXT);

Windows UTF-8 控制台输入(截至 2019 年)仍然有些问题。

编辑:

上述修改还不够。现在,每当我想在 Windows 上支持 UTF-8 代码页和 UNICODE 输入/输出时,我都会执行以下操作(请阅读代码注释以获取更多信息)。

int main()
{
    fflush( stdout );
#if defined _MSC_VER
#   pragma region WIN_UNICODE_SUPPORT_MAIN
#endif
#if defined _WIN32
    // change code page to UTF-8 UNICODE
    if ( !IsValidCodePage( CP_UTF8 ) )
    {
        return GetLastError();
    }
    if ( !SetConsoleCP( CP_UTF8 ) )
    {
        return GetLastError();
    }
    if ( !SetConsoleOutputCP( CP_UTF8 ) )
    {
        return GetLastError();
    }
    
    // change console font - post Windows Vista only
    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
    CONSOLE_FONT_INFOEX cfie;
    const auto sz = sizeof( CONSOLE_FONT_INFOEX );
    ZeroMemory( &cfie, sz );
    cfie.cbSize = sz;
    cfie.dwFontSize.Y = 14;
    wcscpy_s( cfie.FaceName,
        L"Lucida Console" );
    SetCurrentConsoleFontEx( hStdOut,
        false,
        &cfie );
        
    // change file stream translation mode
    _setmode( _fileno( stdout ), _O_U16TEXT );
    _setmode( _fileno( stderr ), _O_U16TEXT );
    _setmode( _fileno( stdin ), _O_U16TEXT );
#endif
#if defined _MSC_VER
#   pragma endregion
#endif
    std::ios_base::sync_with_stdio( false );
    // program:...

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

指南:

  • 在“项目属性”->“常规”->“字符集”中使用“使用 Windows 字符集”
  • 确保您使用支持 unicode utf-8 的终端字体(打开控制台 -> 属性 -> 字体 -> “Lucida 控制台”在 Windows 上是理想的选择)。上面的代码会自动设置。
  • 使用string和 8 位char
  • 使用16位charwchar_twstring)与Windows控制台交互
  • 在应用程序边界使用 8 位charstring例如写入文件、与其他操作系统交互等)
  • 转换string| charwstring| wchar_t用于与 Windows API 交互