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

问题描述 投票:0回答:4

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

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

c++ windows unicode utf-8 windows-xp
4个回答
1
投票

Windows控制台与UNICODE不兼容,尤其是UTF-8。

将控制台代码页设置为utf-8将不起作用。

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

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


1
投票

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

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

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

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

另外,检查this有关cout和控制台的信息。

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


0
投票

出现此问题的原因是,在控制台中使用Windows的代码页与源代码文本文件的编码存在差异。

Qt默认使用utf-8,但另一个编辑器可以使用另一个编辑器。所以你必须验证你正在使用哪一个。

要更改为utf-8使用:

#include <windows.h>

SetConsoleOutputCP(CP_UTF8);

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字形显示大约像。如果用户复制该替换字符,剪贴板将接收原始字形,因此他们可以将其粘贴到其他程序中而不会丢失保真度。

请注意,从mainargv获得的命令行参数将位于原始代码页中。解决这个问题的一种方法是使用GetCommandLineW获取未转换的“宽”命令行,使用WideToMultibyte将其转换为UTF-8,然后自行解析。或者,您可以将GetCommandLineW的结果传递给将解析它的CommandLineToArgvW,然后将每个参数转换为UTF-8。

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

TODO:弄清楚输入。 SetConsoleCP没有按照我认为文档说应该做的那样做。

© www.soinside.com 2019 - 2024. All rights reserved.