【问题标题】:How to print Latin characters to the C++ console properly on Windows?如何在 Windows 上正确地将拉丁字符打印到 C++ 控制台?
【发布时间】:2012-11-03 16:23:13
【问题描述】:

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

La chaîne qui 对应 au 代码 "TEST_CODE" n'a pas été trouvée à l'aide locale "fr"。

这是字符串的打印方式:

La cha¯ne qui 对应 au 代码 "TEST_CODE" n'a pas ÚtÚ trouvÚe Ó l'aide locale "fr"。

我该如何解决这个问题?

【问题讨论】:

  • 我假设您使用的是 Windows?
  • 是的,我会修改我的问题以指定。
  • @Boreal:确保将存储在文件中的字符串转换为 Unicode UTF-16(这对于在 Windows 应用程序中使用的 Unicode 编码是有意义的)。您可以从文件中读取字符串,然后使用MultiByteToWideChar() API(或ATL 转换助手CA2W)将您的特定编码转换为UTF-16。然后,要将 Unicode 字符串打印到控制台,只需使用_setmode(_fileno(stdout), _O_U16TEXT); 初始化控制台,然后可以使用wprintf()std::wcout。有关更多详细信息和链接,请参阅我的答案。

标签: c++ windows unicode console latin


【解决方案1】:

问题在于控制台使用的代码页与系统其他部分不同。例如,通常为美洲和西欧设置的 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 编码在语言环境之间共享。在大多数平台上都是如此——通常在所有语言环境中某些 Unicode 编码用于 wchar_t——但不是全部。


理想情况下,您可以在任何地方都使用 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。

【讨论】:

  • 当你说设置控制台的输出代码页时,我该怎么做呢?
  • @Boreal,使用chcp 命令显示当前代码页或将其设置为其他内容。
  • 我原则上同意这个答案,但代码页似乎不匹配。我找不到与示例输入和输出一致的组合。
  • @MarkRansom 在我看来,重整匹配使用 CP1252 的输入和使用 CP850 的输出
  • 帮世界一个忙,使用CP_UTF8作为参数。 (假设它有效。我还没有测试过。)
【解决方案2】:

如果你想在控制台写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;  
}

考虑阅读 Michael Kaplan 的以下博客文章:

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

【讨论】:

  • 终于按照您的建议得到了éèñçâ...谢谢!我仍然想知道这对西班牙语的解释是如此之少,因为我认为这个舞会中的第二语言!
  • 我没有 _fileno 也没有 _O_U16TEXT。我在哪里可以买到它们?
  • @ploosu2 它们是 Visual C++ 的 CRT 的一部分。您可以在 MSDN 文档中查找它们。
猜你喜欢
  • 2022-01-01
  • 1970-01-01
  • 2013-06-15
  • 2013-02-10
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多