我正在尝试在Windows命令行中输出UTF8字符。我似乎无法获得功能,setConsoleOutputCP
工作。我还听说你必须将字体更改为"Lucida Grande"
才能使用它,但我也无法使用它。有人可以请我提供一个简短的例子,说明如何使用这些函数将UTF-8字符正确输出到控制台吗?
另外我听说这些功能在Windows XP中不起作用,是否有更好的替代方案可以在Windows XP中运行?
Windows控制台与UNICODE不兼容,尤其是UTF-8。
将控制台代码页设置为utf-8将不起作用。
一种方法是使用WideCharToMultiByte()(或其他)将文本转换为UTF-16,然后将MultiByteToWideChar()(或其他)转换为本地化的ISO编码。将控制台代码页设置为ISO代码页。
它的丑陋,但它有点工作。
简而言之:默认情况下,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也一起工作,但这可能会导致非宽字符函数崩溃。
出现此问题的原因是,在控制台中使用Windows的代码页与源代码文本文件的编码存在差异。
Qt默认使用utf-8,但另一个编辑器可以使用另一个编辑器。所以你必须验证你正在使用哪一个。
要更改为utf-8使用:
#include <windows.h>
SetConsoleOutputCP(CP_UTF8);
[我知道这个问题很老,而且是关于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_utf8
中main
变量的定义将代码页更改为UTF-8,并且该代码页将保持有效,直到变量在范围结束时被破坏。
请注意,我在字符串文字上使用了u8
前缀,这是C ++的一个新功能,可确保使用UTF-8对字符串进行编码,而不管源文件使用何种编码。如果您有其他方法可以生成有效的UTF-8文本字符串,则不必使用该功能。
您仍然必须确保CMD窗口使用的字体支持您需要的字形。我认为没有办法自动获取字体链接。但是,如果字体缺少字形,这至少会显示替换字符。例如,在我的窗口,¡Olé!
看起来正确,但CJK字形显示大约像�
。如果用户复制该替换字符,剪贴板将接收原始字形,因此他们可以将其粘贴到其他程序中而不会丢失保真度。
请注意,从main
的argv
获得的命令行参数将位于原始代码页中。解决这个问题的一种方法是使用GetCommandLineW获取未转换的“宽”命令行,使用WideToMultibyte将其转换为UTF-8,然后自行解析。或者,您可以将GetCommandLineW的结果传递给将解析它的CommandLineToArgvW,然后将每个参数转换为UTF-8。
最后,请注意,更改代码页仅影响输出。如果您从用户输入文本,它将使用原始代码页(通常称为OEM代码页)进行编码。
TODO:弄清楚输入。 SetConsoleCP
没有按照我认为文档说应该做的那样做。