如何在Windows上使用C++控制台应用程序打印UTF-8编码的内容

29

对于在英文Windows(XP,Vista或7)上使用Visual Studio 2008编译的C ++控制台应用程序,是否可以使用cout或wcout打印到控制台并正确显示UTF-8编码的日语?


2
在cplusplus.com上有一个有趣的帖子:命令提示符(控制台)中的UTF-8 http://www.cplusplus.com/forum/windows/9797/ - anno
新手请看这里:关于使用Unicode,请查看我的回答 - 关于更改控制台字体,请查看此回答 - Marc.2377
9个回答

18

这应该可以正常工作:

#include <cstdio>
#include <windows.h>

#pragma execution_character_set( "utf-8" )

int main()
{
    SetConsoleOutputCP( 65001 );
    printf( "Testing unicode -- English -- Ελληνικά -- Español -- Русский. aäbcdefghijklmnoöpqrsßtuüvwxyz\n" );
}

不知道它是否会影响任何东西,但源文件被保存为Unicode(带签名的UTF-8) - 代码页65001 ,位于文件-> 高级保存选项...

项目-> 属性-> 配置属性->常规->字符集设置为使用Unicode字符集

有人说需要更改控制台字体为Lucida Console,但在我的电脑上,它显示为Consolas和Lucida Console


默认的cmd控制台是在代码页850中的。这个解决方案似乎在默认设置下不起作用。你改变了其他什么东西吗? - Sandburg
@Sandburg 我不记得改变了其他任何东西,但建议可能与我的Windows本地化为俄语有关。 - Slaus

10

默认情况下,Windows控制台使用OEM代码页显示输出。

要将代码页更改为Unicode,请在控制台中输入chcp 65001,或尝试通过SetConsoleOutputCP以编程方式更改代码页。

请注意,您可能需要更改控制台的字体,以便其具有Unicode范围内的字形。


6
请注意,UTF-8 作为代码页存在许多错误。大部分都不会修复。 - Deduplicator

8

3
一条观察:Michael Kaplan不是MVP。我不知道他是否曾经是。他已经是微软的员工很久了(微软员工不符合MVP计划资格要求)。 - Euro Micelli
此链接指向“资源未找到”。 - Salvador
1
截至2016年08月09日,该链接重定向到http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html,但存在材料(可能是最初在siao2.com上的内容)。 - Jonathan Leffler
3
链接: https://web.archive.org/web/20131118014725/http://blogs.msdn.com/b/michkap/archive/2008/03/18/8306597.aspx这是一篇关于 Unicode 编码和字符集的博客文章。它解释了如何理解 Unicode 中的编码单元、代码点和代码平面。作者还介绍了 Unicode 字符集的历史和发展,并讨论了在软件开发中使用 Unicode 的一些技巧和注意事项。 - ildjarn

4
我从未尝试过将控制台代码页设置为UTF8(不确定为什么它不起作用...控制台可以很好地处理其他多字节代码页),但有几个函数需要查找:SetConsoleCP和SetConsoleOutputCP。
您还需要确保使用的控制台字体能够显示您的字符。 有SetCurrentConsoleFontEx函数,但仅适用于Vista及以上版本。
希望这有所帮助。

1

在应用程序启动时,控制台设置为默认的OEM437 CP。

我试图将Unicode文本输出到stdout,在控制台切换到UTF8模式_setmode(_fileno(stdout), _O_U8TEXT);即使使用Lucida TT字体,仍然无法在屏幕上显示。

如果控制台重定向到文件,则会创建正确的UTF8文件。

最后我很幸运地发现解决方法。我添加了一行代码"info.FontFamily = FF_DONTCARE;",它现在可以正常工作了。

希望这对你有所帮助。

void SetLucidaFont()
{
    HANDLE StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_FONT_INFOEX info;
    memset(&info, 0, sizeof(CONSOLE_FONT_INFOEX));
    info.cbSize = sizeof(CONSOLE_FONT_INFOEX);              // prevents err=87 below
    if (GetCurrentConsoleFontEx(StdOut, FALSE, &info))
    {
        info.FontFamily   = FF_DONTCARE;
        info.dwFontSize.X = 0;  // leave X as zero
        info.dwFontSize.Y = 14;
        info.FontWeight   = 400;
        _tcscpy_s(info.FaceName, L"Lucida Console");
        if (SetCurrentConsoleFontEx(StdOut, FALSE, &info))
        {
        }
    }
}

1
您可以使用 system 调用:
#include <stdlib.h>
#include <stdio.h>

int main() {
    system("chcp 65001");
    printf("%s\n", "中文");
}

0

仅供参考:

'ANSI'是指windows-125x,用于win32应用程序,而'OEM'是指控制台/MS-DOS应用程序使用的代码页。
可以使用GetOEMCP()和GetACP()函数检索当前活动的代码页。

为了正确输出到控制台,您应该:

  1. 确保当前OEM代码页支持您想要输出的字符
    (如果需要,使用SetConsoleOutputCP进行适当设置)

  2. 将字符串从当前ANSI代码(win32)转换为控制台OEM代码页

以下是一些实用工具:

// Convert a UTF-16 string (16-bit) to an OEM string (8-bit) 
#define UNICODEtoOEM(str)   WCHARtoCHAR(str, CP_OEMCP)

// Convert an OEM string (8-bit) to a UTF-16 string (16-bit) 
#define OEMtoUNICODE(str)   CHARtoWCHAR(str, CP_OEMCP)

// Convert an ANSI string (8-bit) to a UTF-16 string (16-bit) 
#define ANSItoUNICODE(str)  CHARtoWCHAR(str, CP_ACP)

// Convert a UTF-16 string (16-bit) to an ANSI string (8-bit)
#define UNICODEtoANSI(str)  WCHARtoCHAR(str, CP_ACP)


/* Convert a single/multi-byte string to a UTF-16 string (16-bit).
 We take advantage of the MultiByteToWideChar function that allows to specify the charset of the input string.
*/
LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) {
    size_t len = strlen(str) + 1;
    int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0);
    LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed);
    MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed);
    return wstr;
}


/* Convert a UTF-16 string (16-bit) to a single/multi-byte string.
 We take advantage of the WideCharToMultiByte function that allows to specify the charset of the output string.
*/
LPSTR WCHARtoCHAR(LPWSTR wstr, UINT codePage) {
    size_t len = wcslen(wstr) + 1;
    int size_needed = WideCharToMultiByte(codePage, 0, wstr, len, NULL, 0, NULL, NULL);
    LPSTR str = (LPSTR) LocalAlloc(LPTR, sizeof(CHAR) * size_needed );
    WideCharToMultiByte(codePage, 0, wstr, len, str, size_needed, NULL, NULL);
    return str;
}

0
在控制台中输入chcp 65001以将代码页更改为UTF-8的代码页。

0

如果有人需要从文件中读取UTF-8并在控制台中打印,可以尝试使用wifstream,即使在Visual Studio调试器中正确显示UTF-8单词(我正在处理繁体中文),参考this post:

#include <sstream>
#include <fstream>
#include <codecvt>

std::wstring readFile(const char* filename)
{
    std::wifstream wif(filename);
    wif.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t>));
    std::wstringstream wss;
    wss << wif.rdbuf();
    return wss.str();
}
 
//  usage
std::wstring wstr2;
wstr2 = readFile("C:\\yourUtf8File.txt");
wcout << wstr2;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接