2023年了,堂堂大微软、宇宙第一IDE竟然连字符集都没法解决or统一,甚至都没有可设置项!虽然编程是全英语环境(ASCII码),但每个国家编写出来的程序肯定要和这个国家的语言打交道,世界上流行的语言也有十多种,只能用ASCII怎么行!
本文实验和记录如何在Visual Studio C++中的控制台、文件存取和json库中正确显示和保存UTF-8字符编码,包括中文、俄文、日文、希腊文和特殊符号等。UTF-8字符编码的好处参见http://utf8everywhere.org/zh-cn。
微软自己有一篇字符编码及转换的文章https://learn.microsoft.com/zh-cn/cpp/text/text-and-strings-in-visual-cpp?view=msvc-170。
实现效果
- 控制台可正确显示UTF-8字符集。
- nlohmann/json库可正确创建包含UTF-8字符的json对象实例。
- 可正确保存包含UTF-8字符串的json格式文件。文件编码为UTF-8 with not BOM(无签名)。
- 可正确读取包含UTF-8字符串的json格式文件。读取后json可正确解析UTF-8字符串。
设置步骤
设置Visual Studio编译
Visual StudioMSVC 编译器选项,将源字符集和执行字符集设置为 UTF-8。
设置后,程序使用fstream等代码生成的文件会保存为UTF-8 with not BOM编码。
设置Visual Studio源文件保存编码
用扩展实现更方便:https://marketplace.visualstudio.com/items?itemName=WinstonFeng.VSFormatOnSave2022。安装扩展后,在VS工具-选项-format on save中,最后一个Enable ForceUtf8WithBom改为True。
Visual Studio菜单-文件-高级保存选项,编码设置为“UNICODE(UTF-8带签名) - 代码页 65001”。如果没找到高级保存选项,参考https://www.cnblogs.com/willingtolove/p/12121577.html。此设置生效范围为当前正在浏览的代码文件,之前已经生成的和未来创建的代码文件的编码仍然是GB2312。所以用扩展实现更方便。
main()函数添加代码
在Main()或wWinMain()函数的开头,添加以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // 开启控制台 AllocConsole(); // 控制台显示乱码纠正 system("chcp 65001"); //设置字符集 (使用SetConsoleCP(65001)设置无效,原因未知) CONSOLE_FONT_INFOEX info = { 0 }; // 以下设置字体 info.cbSize = sizeof(info); info.dwFontSize.Y = 16; // 字体大小 info.FontWeight = FW_NORMAL; wcscpy_s(info.FaceName, L"Consolas"); //你想显示的字体 SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), NULL, &info); freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); freopen_s((FILE**)stdout, "CONOUT$", "w", stderr); freopen_s((FILE**)stdout, "CONIN$", "r", stdin); std::cout.clear(); std::clog.clear(); std::cerr.clear(); std::cin.clear(); // std::wcout, std::wclog, std::wcerr, std::wcin HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); HANDLE hConIn = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); SetStdHandle(STD_OUTPUT_HANDLE, hConOut); SetStdHandle(STD_ERROR_HANDLE, hConOut); SetStdHandle(STD_INPUT_HANDLE, hConIn); std::wcout.clear(); std::wclog.clear(); std::wcerr.clear(); std::wcin.clear(); cout << "cout This works γηυ测试國ふそ▁☒☑■☾•♫¶¤φÇÏÅはにてヌホム㉢ㅆㅔㅃㅋㅝㅘㅎЩОёыфцэыъшмбгжф" << endl; // 开启控制台END |
设置后,程序的控制台就可以正确显示UTF-8字符,不会出现乱码了。
下面是测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <iostream> #include <fstream> #include <nlohmann/json.hpp> using namespace std; using json = nlohmann::json; json j = { {"read",{ {"player_id", { {"addr", 0x011B90C4}, {"offest", {}}, {"comment", "游戏角色的ID"}, }}, {"player_name", { {"addr", 0x011B90B8}, {"offest", {0x10,0x20,0x30}}, {"comment", "γηυ测试國ふそ▁☒☑■☾•♫¶¤φÇÏÅはにてヌホム㉢ㅆㅔㅃㅋㅝㅘㅎЩОёыфцэыъшмбгжф"}, }}, }}, }; try { ofstream o("pretty.json"); o << std::setw(0) << j << std::endl; // read a JSON file std::ifstream k("pretty.json"); json l = json::parse(k); json read = l["read"]; cout << read["player_name"] << endl; } catch (exception& e) { cout << e.what() << endl; } |
文章评论