Unicode字符不读 - C ++

时间:2015-02-24 21:15:19

标签: c++ file unicode

我有一段简单的代码可以打开文件流&打印出来的东西。 一旦它击中一个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();

输出:

Output

2 个答案:

答案 0 :(得分:2)

它读得很好,它只是不写作。

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

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

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

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

将当前代码页设置为65001以尝试获得所有其他现代平台所需的相同UTF-8输出,但由于基本C运行时中存在各种多字节字符计数错误而无法正常工作。 MS已经将这个版本留下了许多版本,所以期望UTF-8在Windows下仍然是二等公民。

一些替代方案:

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

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

  3. 显式输出UTF-8编码的字节,并要求Windows控制台用户只是忍受导致的mojibake和缺少的字形。

  4. 遗憾的是,这个故事仍然很悲惨。

答案 1 :(得分:0)

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直接相关的输出

我确实写了一周或两周的unicode测试。它可能会对您有所帮助,请参阅https://github.com/MagnusTiberius/wcutil/blob/master/widechartest.cpp了解详细信息。

您可能还想查看如何设置代码页以呈现双/多字节。

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