如何从 Windows 上的 c++ 控制台应用程序打印 UTF-8

Posted

技术标签:

【中文标题】如何从 Windows 上的 c++ 控制台应用程序打印 UTF-8【英文标题】:How do I print UTF-8 from c++ console application on Windows 【发布时间】:2010-11-25 03:42:49 【问题描述】:

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

【问题讨论】:

cplusplus.com 上有一个有趣的话题:UTF-8 in command prompt (console) cplusplus.com/forum/windows/9797 新手: Check my answer here 使用 unicode - 并检查 this answer 更改控制台字体。 【参考方案1】:

对于任何需要从文件读取 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;

【讨论】:

【参考方案2】:

仅供参考:

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

为了向控制台正确输出某些内容,您应该:

    确保当前 OEM 代码页支持您要输出的字符 (如有必要,使用 SetConsoleOutputCP 正确设置)

    将字符串从当前 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;

【讨论】:

【参考方案3】:

这应该可行:

#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)- FILE -> 处的代码页 65001高级保存选项...

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

有人说您需要将控制台字体更改为 Lucida Console,但在我这边,它同时显示为 ConsolasLucida Console

【讨论】:

默认 cmd 控制台位于代码页 850 中。此解决方案似乎不适用于该默认设置。你有没有改变别的东西? @Sandburg 我不记得更改任何其他内容,但建议这可能与我的 Windows 被本地化为俄语有关。【参考方案4】:

在应用启动控制台设置为默认 OEM437 CP。 我试图将 Unicode 文本输出到标准输出,其中控制台切换到 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))
        
        
    

【讨论】:

【参考方案5】:

Here's an article from MVP Michael Kaplan 关于如何通过控制台正确输出 UTF-16。您可以将 UTF-8 转换为 UTF-16 并输出。

【讨论】:

一个观察:Michael Kaplan 不是 MVP。我不知道他是否曾经。他多年来一直是 Microsoft 员工(Microsoft 员工没有资格参加 MVP 计划)。 这个链接带来Resource Not Found 截至 2016 年 8 月 9 日,链接重定向到 archives.miloush.net/michkap/archive/2008/03/18/8306597.html,但有材料存在(大概是 siao2.com 最初的内容)。 固定链接:web.archive.org/web/20131118014725/http://blogs.msdn.com/b/…【参考方案6】:

我实际上从未尝试将控制台代码页设置为 UTF8(不知道为什么它不起作用......控制台可以处理其他多字节代码页就好了),但是有几个要查找的函数:SetConsoleCP 和 SetConsoleOutputCP。

您可能还需要确保您使用的控制台字体能够显示您的角色。有SetCurrentConsoleFontEx 功能,但仅适用于Vista 及更高版本。

希望对您有所帮助。

【讨论】:

【参考方案7】:

Windows 控制台默认使用OEM code page 来显示输出。

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

请注意,您可能必须将控制台的字体更改为具有 unicode 范围内的字形的字体。

【讨论】:

请注意,使用 UTF-8 作为代码页存在许多错误。大多数是 WONTFIX。【参考方案8】:

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

【讨论】:

以上是关于如何从 Windows 上的 c++ 控制台应用程序打印 UTF-8的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 WinAPI 和 C++ 从 Windows 系统上的服务通知客户端应用程序?

如何从 Windows 上的 Java 控制台应用程序确定当前活动的代码页?

控制和分析内存和时间消耗 C++ Windows 应用程序? [关闭]

使用 COM 在 Windows 上的本地计算机上进行进程间通信

C++ CreateProcess 无法从 Windows 7 上的套接字接收路径 (64)

写入在 Windows 下的 Java 应用程序中生成的 C++ 控制台应用程序