我知道这已经很老了,但我必须自己解决它,然后就可以了。
这个想法是在 Unicode 的 UTF-8 和 UTF-32 编码之间切换:您可以计算 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;
}
如果你愿意,你可以在类中、在构造函数中、在模板中或任何你喜欢的地方实现这个函数。
使用 char 数组跟随重载运算符
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;
}
导致?€ 打印在 (Linux) 控制台上。不过,这应该使用不同的 Unicode 字符进行测试...
这也因字节顺序而异,但我相信您可以通过 this 找到解决方案。