如何使用 C++ 在 Windows 中输出和输入 UTF8 或 UTF16 Unicode 文本?

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

这是我的程序:

#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;
}

假设我想支持希腊语编码(对于 输入和输出)。如果我设置了适当的编码并且当然删除了 fflush(stdout)_setmode().

,则该程序在 Linux 上可以完美地用于各种输出和输入语言

所以 Windows 当我使用 std::locale::global(loc) 时,该程序将正确输出希腊语(和英语),但它不会接受我从键盘输入的希腊语输入。如果我输入希腊语,std::wcout << yes 会输出乱码或问号。显然 ::global 在 Windows 上并不是真正的全球性?

所以我在 wcoutwcin 上尝试了 .imbue() 方法(它也适用于 Linux),您会在此处看到注释掉的方法。当我使用这两个语句中的任何一个和 运行 程序时,它会(正确编译)向我显示提示,当我按 w/e 然后按 'enter' 它只是简单地退出而没有错误或诸如此类。

我尝试了一些 Windows 特定命令,但后来我也感到困惑。我不清楚我应该尝试什么以及何时开启 Windows。

所以问题是我如何才能像上面的程序一样在 Windows 中正确输入和输出希腊文本?我使用 MSVS 2017 最新更新。提前致谢。

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

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

编辑:

以上修改还不够。现在,只要我想在 Windows 上支持 UTF-8 代码页和 UNICODE input/output(阅读代码注释以获取更多信息),我就会执行以下操作。

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;
}

指南:

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