如何在Windows上正确地将拉丁字符打印到C++控制台
How to print Latin characters to the C++ console properly on Windows?
我在用C++向控制台写入法语字符时遇到问题。该字符串使用std::ifstream
和std::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
。
- 无符号字符打印其 ASCII 值
- 我正在尝试为字符打印一些相应的值,但条件总是转到其他位置
- 为什么完整的字符串没有一次打印,但是当我尝试逐个字符打印时
- 延迟逐个字符打印单词
- C++:如何将 unicode 字符打印到文本文件
- 为什么 std::hex 没有特别用字符打印为十六进制?
- 使用 C++ 将 UTF8 字符打印到 Linux 控制台
- 如何在Windows上正确地将拉丁字符打印到C++控制台
- 使用线程根据起始字符打印出单词
- 每隔n个字符打印一行换行符
- C++奇怪的字符打印到屏幕上
- 将字符打印为整数
- C++ 将文本文件的单个字符打印到屏幕
- C++递归字符打印
- 使用WritePrinter API将中文字符打印到Line Printer
- c++ Unicode字符打印
- 将UTF-32字符打印到终端
- 使用cout将数组和字符打印到屏幕时出现意外结果
- 为重复字符打印星号的算法
- 用于循环字符打印