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 公民
一些备选方案:
使用 Win32 WriteConsoleW
API 而不是 stdlib 接口。 (需要小心处理可能的输出重定向,如果你需要你的项目是跨平台兼容的。)
使用 _setmode
和 _O_U16TEXT
将输出流更改为 UTF-16 编码字节。请参阅 this question 中的示例。似乎并非所有接口都必须在这种模式下工作;如果您尝试同时使用字节接口,您可能会遇到麻烦。
输出显式 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/
我有一段简单的代码可以打开文件流并打印出内容。 一旦遇到 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 公民一些备选方案:
使用 Win32
WriteConsoleW
API 而不是 stdlib 接口。 (需要小心处理可能的输出重定向,如果你需要你的项目是跨平台兼容的。)使用
_setmode
和_O_U16TEXT
将输出流更改为 UTF-16 编码字节。请参阅 this question 中的示例。似乎并非所有接口都必须在这种模式下工作;如果您尝试同时使用字节接口,您可能会遇到麻烦。输出显式 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/