Unicode 字符不读 - C++

Unicode Character Not Reading - C++

我有一段简单的代码可以打开文件流并打印出内容。 一旦遇到 unicode 字符,它就会停止读取。

我的系统设置为日语语言环境,Visual Studio 设置为编译为 unicode。不确定发生了什么。

文件:

<abc \ 单位孤>hajslklfasjflkesjfleajflj

文件十六进制转储:

EF BB BF 3C 61 62 63 20 5C 20 E5 8D 95 E4 BD 8D
E5 AD A4 3E 68 61 6A 73 6C 6B 6C 66 61 73 6A 66
6C 6B 65 73 6A 66 6C 65 61 6A 66 6C 6A 0D 0A

代码部分:

std::wifstream fin(path, std::ios::binary);
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8_utf16<wchar_t, 0x10ffff, std::consume_header>));
if (!fin.good()) return;

while (fin.good()) {
    std::wcout << (wchar_t)fin.get() << "\n";
}

fin.close();

输出:

读的还好,就是写的不行

std::wcout << (wchar_t)fin.get() << "\n";

不幸的是 std::wcout 实际上并不能可靠地将 Unicode 发送到终端。

虽然 Windows 终端在 UTF-16 代码单元中本地工作,但 std::wcout 仍然以纯粹基于字节的术语定义。它使用特定于语言环境的默认编码将其宽输入向下转换为字节,然后再写入良好的旧 Unicode 无知字节标准输出流(毕竟这可能是本机字节文件重定向以及本机 Unicode 终端输出) .

所以 std::wcout 最终与所有其他字节 IO 接口一样在 Windows 下受到限制,仅限于当前代码页中的字符。您的代码页可能是 932,其中字符 U+5355 不存在,因此尝试写入它会中断流。

由于基本 C 运行时中的各种多字节字符计数错误,将当前代码页设置为 65001 以尝试获得所有其他现代平台喜欢的相同 UTF-8 输出并不完全有效。 MS 已经为许多多个版本留下了这个问题,因此希望 UTF-8 在 Windows.

下仍然是第二个 class 公民

一些备选方案:

  1. 使用 Win32 WriteConsoleW API 而不是 stdlib 接口。 (需要小心处理可能的输出重定向,如果你需要你的项目是跨平台兼容的。)

  2. 使用 _setmode_O_U16TEXT 将输出流更改为 UTF-16 编码字节。请参阅 this question 中的示例。似乎并非所有接口都必须在这种模式下工作;如果您尝试同时使用字节接口,您可能会遇到麻烦。

  3. 输出显式 UTF-8 编码的字节并要求 Windows 控制台用户只能忍受 mojibake 和丢失的字形。

可惜这个故事还是那么凄惨

std::wcout 可能与它有关。

试试这个页面:https://alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode/

//std::locale loc2 = std::locale("zh-CN");
//SetConsoleOutputCP(CP_UTF8);
//SetConsoleCP(65001);
_setmode(_fileno(stdout), _O_U16TEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
_setmode(_fileno(stdout), _O_WTEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
//setlocale(LC_ALL, "C");
//fputs("hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ\n", stdout);
std::wcout << "text:" << L"hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ" << "\n";
wprintf(L">>> hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ \n");
std::locale loc3 = std::locale("en-US");
_setmode(_fileno(stdout), _O_U16TEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
_setmode(_fileno(stdout), _O_WTEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
_setmode(_fileno(stdout), _O_U8TEXT);
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n";
//setlocale(LC_ALL, "C");
//fputs("hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ\n", stdout);
std::wcout << "text:" << L"hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ" << "\n";
wprintf(L">>> hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ \n");

根据您输入 chcp intvalue 命令的方式,您将获得与代码页 1252 和 65001[=14 直接相关的输出=]

我确实在一两周前写了一个 unicode 测试。说不定对你有帮助,详见https://github.com/MagnusTiberius/wcutil/blob/master/widechartest.cpp

您可能还想查看如何设置代码页以呈现 double/multi-byte。

http://www.curlybrace.com/words/2014/10/03/windows-console-and-doublemulti-byte-character-set/