Warm tip: This article is reproduced from serverfault.com, please click

c++-如何在Windows上将UTF-8字符串打印到std :: cout?

(c++ - How to print UTF-8 strings to std::cout on Windows?)

发布于 2017-08-08 18:45:55

我正在用C ++编写一个跨平台的应用程序。所有字符串在内部都是UTF-8编码的。考虑以下简化代码:

#include <string>
#include <iostream>

int main() {
    std::string test = u8"Greek: αβγδ; German: Übergrößenträger";
    std::cout << test;

    return 0;
}

在Unix系统上,std::cout期望8位字符串采用UTF-8编码,因此此代码可以正常工作。

但是,在Windows上,std::cout期望8位字符串采用Latin-1或类似的非Unicode格式(取决于代码页)。这将导致以下输出:

希腊文:╬▒╬▓╬│╬┤; 德语:├£bergr├Â├ƒentr├ñger

std::cout在Windows上我该怎么做才能将8位字符串解释为UTF-8?

这是我尝试的:

#include <string>
#include <iostream>
#include <io.h>
#include <fcntl.h>

int main() {
    _setmode(_fileno(stdout), _O_U8TEXT);
    std::string test = u8"Greek: αβγδ; German: Übergrößenträger";
    std::cout << test;

    return 0;
}

我希望那_setmode能达到目的。但是,这导致在调用的行中出现以下断言错误operator<<

Microsoft Visual C ++运行时库

调试断言失败!

程序:d:\ visual studio 2015 \ Projects \ utf8test \ Debug \ utf8test.exe文件:minkernel \ crts \ ucrt \ src \ appcrt \ stdio \ fputc.cpp行:47

表达式:((_Stream.is_string_backed())||(fn = _fileno(_Stream.public_stream()),((__textmode_safe(fn)== __crt_lowio_text_mode :: ansi)&&!_tm_unicode_safe(fn))))

有关程序如何导致断言失败的信息,请参见有关断言的Visual C ++文档。

Questioner
Daniel Wolf
Viewed
0
mkluwe 2017-08-16 02:59:45

问题不std::cout只是Windows控制台。使用C-标准输入输出,你将获得üfputs( "\xc3\xbc", stdout );设置UTF-8代码页后(使用SetConsoleOutputCPchcp,并设置在cmd中的设置一个Unicode支持字体(索拉应该支持超过2000个字符,并有注册表黑客以更强大的字体到CMD) 。

如果在一个字节之后一个字节输出,putc('\xc3'); putc('\xbc');则会得到双豆腐,因为控制台会将它们分别解释为非法字符。这可能就是C ++流所做的。

有关冗长的讨论,请参见Windows控制台上的UTF-8输出

对于我自己的项目,我最终实现了std::stringbuf向Windows-1252的转换。我确实需要完整的Unicode输出,但是,这并不能真正帮助你。

另一种方法是覆盖cout的streambuf,fputs用于实际输出:

#include <iostream>
#include <sstream>

#include <Windows.h>

class MBuf: public std::stringbuf {
public:
    int sync() {
        fputs( str().c_str(), stdout );
        str( "" );
        return 0;
    }
};

int main() {
    SetConsoleOutputCP( CP_UTF8 );
    setvbuf( stdout, nullptr, _IONBF, 0 );
    MBuf buf;
    std::cout.rdbuf( &buf );
    std::cout << u8"Greek: αβγδ\n" << std::flush;
}

我在这里关闭了输出缓冲,以防止它干扰未完成的UTF-8字节序列。