我在你的另一个问题中已经给你提供了很好的答案。这是类似的东西。
你的程序可以使用UTF-8
编码和控制台可以使用不同的编码,但是您必须向标准库提供如何对每个数据源进行编码的提示。
当然,如果目标编码没有涵盖不支持特定字符,则必须启动一些后备(请参见底部的示例)。
必须明确定义编码才能使一切正常工作的 4 个领域:
- 你的源代码。 VS 使用系统区域设置来使用编码,这很糟糕。强制 VS 和所有编辑器使用通用编码,UTF-8 选择是最好的。最好告知编译器源代码是如何编码的:
cl /source-charset:utf-8 .....
- 你的可执行文件。您必须定义在最终可执行文件中应编码哪种编码字符串文字。这里
UTF-8
也是最好的:cl .... /execution-charset:utf-8 .....
- 当您运行应用程序时,您必须告知标准库您的字符串文字定义的编码类型或程序逻辑中使用的编码类型。因此,在执行开始时,代码中的某个位置需要这样的内容:
std::locale::global(std::locale{".utf-8"});
- 最后你必须指示流应该使用哪种编码。因此对于
std::cout
and std::cin
您应该设置系统默认的区域设置:
auto streamLocale = std::locale{""};
// this impacts date/time/floating point formats, so you may want tweak it just to use sepecyfic encoding and use C-loclae for formating
std::cout.imbue(streamLocale);
std::cin.imbue(streamLocale);
之后,一切都应该按预期工作,无需显式进行转换的代码。
由于有 4 个地方会出错,这就是人们遇到麻烦的原因,并且互联网上充满了“黑客”解决方案。
这是一些测试程序来证明我的观点:
#include <iostream>
#include <locale>
#include <exception>
#include <string>
void setupLocale(int argc, const char *argv[])
{
std::locale def{""};
std::locale::global(argc > 1 ? std::locale{argv[1]} : def);
auto streamLocale = argc > 2 ? std::locale{argv[2]} : def;
std::cout.imbue(streamLocale);
std::cin.imbue(streamLocale);
}
void printSeparator()
{
std::cout << "---------\n";
}
void printTestStuff()
{
std::cout << "Wester Europe: āāāčččēēēēßÞÖöñÅÃ\n";
std::cout << "Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă\n";
std::cout << "China: 字集碼是把字符集中的字符编码为指定集合中某一对象\n";
std::cout << "Korean: 줄여서 인코딩은 사용자가 입력한\n";
}
int main(int argc, const char *argv[]) {
try{
setupLocale(argc, argv);
printSeparator();
printTestStuff();
printSeparator();
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
}
以及它是如何构建和运行以显示其工作原理的(请注意,这也涵盖了使用无效编码的情况):
C:\Users\User\Downloads>cl /source-charset:utf-8 /execution-charset:utf-8 /EHsc encodings.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.28.29336 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
encodings.cpp
Microsoft (R) Incremental Linker Version 14.28.29336.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:encodings.exe
encodings.obj
C:\Users\User\Downloads>chcp
Active code page: 437
C:\Users\User\Downloads>encodings.exe
---------
Wester Europe: Ä?Ä?Ä?Ä?Ä?Ä?Ä"Ä"Ä"Ä"AYAzA-AA±A.Aƒ
Central Europe: Ä.Ä,A"A3Å?Å,Ä~ÄTżÄ╪źŰűA?A½Ä,ă
China: å--é>+碼æ~_æSSå--ç¬▌é>+ä,-çs,å--ç¬▌ç¼-ç ?ä,ºæO╪årsé>+å?^ä,-æY?ä,?å_1象
Korean: ì,ì-¬ì,o ì?,ì½"ë"cì?? ì,¬ìscìz?ê°? ìz.ë ¥ío
---------
C:\Users\User\Downloads>encodings.exe .65001
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------
C:\Users\User\Downloads>encodings.exe .65001 .437
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------
C:\Users\User\Downloads>encodings.exe .65001 .1250
---------
Wester Europe: aaaccceeeeß_ÖöñÅA
Central Europe: aAOóLlEezczUuYyAa
China: ????????????????????????
Korean: ??? ???? ???? ???
---------
C:\Users\User\Downloads>chcp 1250
Active code page: 1250
C:\Users\User\Downloads>encodings.exe .65001 .1250
---------
Wester Europe: aaačččeeeeß?ÖönAA
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: ????????????????????????
Korean: ??? ???? ???? ???
---------
C:\Users\User\Downloads>chcp 65001
Active code page: 65001
C:\Users\User\Downloads>encodings.exe
---------
Wester Europe: ÄÄÄÄÄÄēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóÅłĘężćźŰűÃýĂă
China: å—集碼是把å—符集ä¸çš„å—符编ç 为指定集åˆä¸æŸä¸€å¯¹è±¡
Korean: 줄여서 ì¸ì½”ë”©ì€ ì‚¬ìš©ìžê°€ ìž…ë ¥í•œ
---------
C:\Users\User\Downloads>encodings.exe .65001
---------
Wester Europe: āāāčččēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: 字集碼是把字符集中的字符编码为指定集合中某一对象
Korean: 줄여서 인코딩은 사용자가 입력한
---------
C:\Users\User\Downloads>encodings.exe .65001 .65001
---------
Wester Europe: āāāčččēēēēßÞÖöñÅÃ
Central Europe: ąĄÓóŁłĘężćźŰűÝýĂă
China: 字集碼是把字符集中的字符编码为指定集合中某一对象
Korean: 줄여서 인코딩은 사용자가 입력한
---------
C:\Users\User\Downloads>