在Windows C ++中更改控制台代码页

时间:2014-05-05 11:58:32

标签: c++ windows unicode utf-8 windows-xp

我试图在Windows命令行中输出UTF8字符。我似乎无法使用setConsoleOutputCP功能。我还听说你必须将字体更改为"Lucida Grande"才能使其工作,但我也无法正常工作。有人可以请我提供一个简短的例子,说明如何使用这些函数将UTF-8字符正确输出到控制台吗?

另外我听说这些功能在Windows XP中不起作用,是否有更好的替代方案可以在Windows XP中运行?

4 个答案:

答案 0 :(得分:1)

Windows控制台与UNICODE,尤其是UTF-8不相称。

将控制台代码页设置为utf-8无法正常工作。

一种方法是使用WideCharToMultiByte()(或其他)将文本转换为UTF-16,然后将MultiByteToWideChar()(或其他)转换为本地化的ISO编码。将控制台代码页设置为ISO代码页。

它的丑陋,但它有点工作。

答案 1 :(得分:1)

简而言之:默认情况下,SetConsoleOutputCP CP_UTF8和cout / wcout不能一起使用。

尽管Windows CRT支持utf-8输出,但输出到控制台utf-8字符的一种强大方法是将它们转换为控制台当前代码页,特别是如果你想使用count / wcout。 默认情况下,basic_ostream的标准高级功能无法正常使用utf-8。

我已经看到MultiByteToWideChar和WideCharToMultiByte与CP_OEMCP和CP_UTF8参数一起使用。

您可以通过SetCurrentConsoleFontEx设置应用程序环境,包括控制台字体,但它仅适用于Vista和Server 2008。

另外,请检查this有关cout和console的信息。

_setmode和wprintf一起工作,但这可能会导致非宽字符函数崩溃。

答案 2 :(得分:0)

之所以会出现此问题,是因为使用控制台中的窗口和源代码文本文件的编码的代码页有所不同。

Qt默认使用utf-8,但是另一个编辑器可以使用另一个。因此,您必须验证您使用的是哪一个。

要更改为utf-8,请使用:

#include <windows.h>

SetConsoleOutputCP(CP_UTF8);

答案 3 :(得分:0)

[我知道这个问题很旧,并且是关于Windows XP的,但是似乎仍然是删除此信息的好地方,因此我(也许还有其他人)可以在将来再次找到它。]

在较新版本的Windows中,对CMD窗口中Unicode的支持得到了改进。该程序将在Windows 10上运行。

#include <iostream>
#include <Windows.h>

class UTF8CodePage {
  public:
    UTF8CodePage() : m_old_code_page(::GetConsoleOutputCP()) {
      ::SetConsoleOutputCP(CP_UTF8);
    }
    ~UTF8CodePage() { ::SetConsoleOutputCP(m_old_code_page); }

  private:
    UINT m_old_code_page;
};

int main() {
  UTF8CodePage use_utf8;
  const char *text = u8"This text is in UTF-8. ¡Olé! 佻\n";
  std::cout << text;
  return 0;
}

我制作了RAII类来确保恢复代码页,因为如果用户有意选择了特定代码页,则保留更改代码页的做法是不礼貌的。所有特定于Windows的代码(SetConsoleOutputCP)都包含在该类中。 use_utf8main变量的定义将代码页更改为UTF-8,并且该代码页将一直有效,直到该变量在作用域末尾被破坏为止。

请注意,我在字符串文字上使用了u8前缀,这是C ++的新功能,可以确保使用UTF-8对字符串进行编码,而与源文件所使用的编码无关。如果您有另一种方法来生成有效的UTF-8文本字符串,则不必使用该功能。

您仍然必须确保CMD窗口使用的字体支持所需的字形。我认为没有办法自动获得字体链接。  但是,如果字体缺少字形,则至少会显示一个替换字符。例如,在我的窗口中,¡Olé!看起来正确,但是CJK字形的显示大致类似于。如果用户复制了该替换字符,则剪贴板将收到原始字形,因此他们可以将其粘贴到其他程序中,而不会损失任何保真度。

请注意,您从main的{​​{1}}获取的命令行参数将在原始代码页中。解决此问题的一种方法是使用GetCommandLineW获取未转换的“宽”命令行,使用WideToMultibyte将其转换为UTF-8,然后自己进行解析。另外,您可以将GetCommandLineW的结果传递到CommandLineToArgvW,它将对其进行解析,然后将每个参数转换为UTF-8。

最后,请注意,更改代码页仅影响输出。如果您输入的是用户文字,则文字会使用原始代码页(通常称为OEM代码页)进行编码。

TODO:找出输入。 argv并没有按照我认为文档应该做的做。