如何在Windows上正确地将拉丁字符打印到C++控制台

How to print Latin characters to the C++ console properly on Windows?

本文关键字:字符 打印 控制台 C++ 丁字符 Windows 正确地      更新时间:2023-10-16

我在用C++向控制台写入法语字符时遇到问题。该字符串使用std::ifstreamstd::getline从文件加载,然后使用std::cout打印到控制台。以下是文件中的字符串:

La chaîne需要对应代码"TEST_code",这是一个辅助语言环境"fr"。

下面是字符串的打印方式:

La cha’ne qui对应于代码"TEST_code",这是一个"fr"的区域设置。

如何解决此问题?

问题是控制台使用的代码页与系统其他部分不同。例如,通常为美洲和西欧设置的Windows系统使用CP1252,但这些地区的控制台使用CP437或CP850。

您可以将控制台输出代码页设置为与正在使用的编码相匹配,也可以将字符串转换为与控制台的输出代码页相匹配。

设置控制台输出代码页:

SetConsoleOutputCP(GetACP()); // GetACP() returns the system codepage.
std::cout << "La chaîne qui correspond au code "TEST_CODE" n'a pas été trouvée à l'aide locale "fr".";

或者在编码之间转换的多种方法之一(此方法需要VS2010或更高版本):

#include <codecvt> // for wstring_convert
#include <locale>  // for codecvt_byname
#include <iostream>
int main() {
typedef std::codecvt_byname<wchar_t,char,std::mbstate_t> codecvt;
// the following relies on non-standard behavior, codecvt destructors are supposed to be protected and unusable here, but VC++ doesn't complain.
std::wstring_convert<codecvt> cp1252(new codecvt(".1252"));
std::wstring_convert<codecvt> cp850(new codecvt(".850"));
std::cout << cp850.to_bytes(cp1252.from_bytes("...été trouvée à...n")).c_str();
}

后一个示例假设您实际上需要在1252和850之间进行转换。您可能应该使用函数GetOEMCP()来计算实际的目标代码页,而源代码页实际上取决于您对源代码使用的内容,而不是运行程序的机器上GetACP()的结果。

还要注意的是,这个程序依赖于一些标准无法保证的东西:wchar_t编码在区域设置之间共享。在大多数平台上都是如此—通常,wchar_t在所有地区都使用一些Unicode编码—但不是全部。


理想情况下,您可以在任何地方使用UTF-8,下面的操作都会很好,就像现在在其他平台上一样:

#include <iostream>
int main() {
std::cout << "La chaîne qui correspond au code "TEST_CODE" n'a pas été trouvée à l'aide locale "fr".n";
}

不幸的是,如果不放弃UTF-16作为wchar_t编码并采用4字节的wchar_t,或者违反标准要求并破坏符合标准的程序,Windows就无法以这种方式支持UTF-8。

如果你想在控制台中编写Unicode字符,你必须进行一些初始化

_setmode(_fileno(stdout), _O_U16TEXT);

然后你的法语字符就会正确显示(我已经用Consolas作为控制台字体进行了测试):

#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <ostream>
#include <string>
using namespace std;
int main() 
{
// Prepare console output in Unicode
_setmode(_fileno(stdout), _O_U16TEXT);

//
// Build Unicode UTF-16 string with French characters
//
// 0x00EE - LATIN SMALL LETTER I WITH CIRCUMFLEX
// 0x00E9 - LATIN SMALL LETTER E WITH ACUTE
// 0x00E0 - LATIN SMALL LETTER A WITH GRAVE
wstring str(L"La cha");
str += L'x00EE';
str += L"ne qui correspond au code "TEST_CODE" ";
str += L"n'a pas ";
str += L'x00E9';
str += L't';
str += L'x00E9';
str += L" trouv";
str += L'x00E9';
str += L"e ";
str += L'x00E0';
str += L" l'aide locale "fr".";

// Print the string to the console
wcout << str << endl;  
}

考虑阅读迈克尔·卡普兰的以下博客文章:

  • 打破控制台中的神话
  • 传统智慧是迟钝的,也就是什么@#%&*是_O_U16TEXT

此外,如果您正在从文件中读取一些文本,您必须知道使用了哪种编码:UTF-8?UTF-16LE?UTF-16BE?一些特定的代码页?然后,您可以从特定编码转换为Unicode UTF-16,并在Windows应用程序中使用UTF-16。要从某些代码页(或UTF-8)转换为UTF-16,可以使用MultiByteToWideChar()API或ATL转换帮助类CA2W