如何在C++11中使用(cout
/ wcout
/ ...)打印char32_t到控制台?
下面的代码打印十六进制值:
u32string s2 = U"Добрый день";
for(auto x:s2){
wcout<<(char32_t)x<<endl;
}
首先,我认为wcout
不应该打印除char
和wchar_t
之外的任何字符。char32_t
也不是。
下面是一个打印单个wchar_t
的示例程序:
#include <iostream>
using namespace std;
int main()
{
wcout << (wchar_t)0x41 << endl;
return 0;
}
输出 (ideone):
A
目前,即使在主要的操作系统中,控制台也无法提供一致的Unicode输出。通过cout
、wcout
、printf()
、wprintf()
等简单的Unicode文本输出,在Windows上不会起作用,除非进行重大改进。在Windows控制台中获取可读的Unicode文本的问题在于拥有并能够选择适当的Unicode字体。在这方面,Windows控制台相当失灵。请参见我的这个答案并跟随其中的链接。
我知道这已经很老了,但我不得不自己解决它,然后你就可以开始了。 思路是在UTF-8和UTF-32编码之间切换Unicode:您可以cout u8字符串,因此只需将UTF-32编码的char32_t翻译成它即可。以下是我想出来的低级功能(没有现代C++)。可能可以进行优化,也欢迎任何建议。
char* char_utf32_to_utf8(char32_t utf32, const char* buffer)
// Encodes the UTF-32 encoded char into a UTF-8 string.
// Stores the result in the buffer and returns the position
// of the end of the buffer
// (unchecked access, be sure to provide a buffer that is big enough)
{
char* end = const_cast<char*>(buffer);
if(utf32 < 0x7F) *(end++) = static_cast<unsigned>(utf32);
else if(utf32 < 0x7FF) {
*(end++) = 0b1100'0000 + static_cast<unsigned>(utf32 >> 6);
*(end++) = 0b1000'0000 + static_cast<unsigned>(utf32 & 0b0011'1111);
}
else if(utf32 < 0x10000){
*(end++) = 0b1110'0000 + static_cast<unsigned>(utf32 >> 12);
*(end++) = 0b1000'0000 + static_cast<unsigned>((utf32 >> 6) & 0b0011'1111);
*(end++) = 0b1000'0000 + static_cast<unsigned>(utf32 & 0b0011'1111);
} else if(utf32 < 0x110000) {
*(end++) = 0b1111'0000 + static_cast<unsigned>(utf32 >> 18);
*(end++) = 0b1000'0000 + static_cast<unsigned>((utf32 >> 12) & 0b0011'1111);
*(end++) = 0b1000'0000 + static_cast<unsigned>((utf32 >> 6) & 0b0011'1111);
*(end++) = 0b1000'0000 + static_cast<unsigned>(utf32 & 0b0011'1111);
}
else throw encoding_error(end);
*end = '\0';
return end;
}
如果您愿意,可以在类中、构造函数中、模板中或任何您喜欢的方式中实现此函数。
使用字符数组重载运算符。
std::ostream& operator<<(std::ostream& os, const char32_t* s)
{
const char buffer[5] {0}; // That's the famous "big-enough buffer"
while(s && *s)
{
char_utf32_to_utf8(*(s++), buffer);
os << buffer;
}
return os;
}
同时使用u32string
std::ostream& operator<<(std::ostream& os, const std::u32string& s)
{
return (os << s.c_str());
}
用维基百科上发现的Unicode字符运行最简单、最愚蠢的测试
int main()
{
std::cout << std::u32string(U"\x10437\x20AC") << std::endl;
}
€
。尽管如此,应该使用不同的Unicode字符进行测试... 此外,这也会因字节序而异,但我相信您可以在这里找到解决方案。
wcout
不应该打印除char
和wchar_t
以外的任何字符。char32_t
也不是其中之一。 - Alexey Frunze*cout
打印任何“可读”的内容,我是否需要将这些字符转换为utf8(如果可能的话)? - Wojciech Danilo