iostreams - 将"wchar_t"或"charXX_t"值打印为字符

iostreams - Print `wchar_t` or `charXX_t` value as a character

本文关键字:quot 打印 字符 charXX wchar iostreams      更新时间:2023-10-16

如果将wchar_tchar16_tchar32_t值馈送到窄流,它将打印代码点的数值。

#include <iostream>
using std::cout;
int main()
{
cout << 'x' << L'x' << u'x' << U'x' << 'n';
}

打印x120120120. 这是因为basic_ostream与其charT的特定组合有一个operator<<,但其他字符类型没有类似的运算符,因此它们被静默转换为int并以这种方式打印。 类似地,非窄字符串文本(L"x"u"x"U"X")将被静默转换为void*并打印为指针值,而非窄字符串对象(wstringu16stringu32string)甚至不会编译。

那么,问题来了:在狭窄的数据流上打印wchar_tchar16_tchar32_t值作为字符而不是代码点的数值的最不可怕的方法是什么? 它应将 ostream 编码中可表示的所有代码点正确转换为该编码,并且应在代码点不可表示时报告错误。 (例如,给定u'…'和 UTF-8 ostream,应将三字节序列0xE2 0x80 0xA6写入流;但给定u'â'和 KOI8-R ostream,应报告错误。

同样,如何在窄流上打印非窄 C 字符串或字符串对象,转换为输出编码?

如果在ISO C++11中无法做到这一点,我将采用特定于平台的答案。

(灵感来自这个问题。

正如您所指出的,狭窄的ostream没有operator<<(std::ostream&, const wchar_t)。但是,如果您想使用该语法,您可以教ostream如何使用wchars,以便将该例程选为比需要首先转换为整数的例程更好的重载。

如果您喜欢冒险:

namespace std {
ostream& operator<< (ostream& os, wchar_t wc) {
if(unsigned(wc) < 256) // or another upper bound
return os << (unsigned char)wc;
else
throw your_favourite_exception; // or handle the error in some other way
}
}

否则,制作一个简单的struct,透明地包含wchar_t并具有自定义friend operator<<,并在输出之前将宽字符转换为该字符。

编辑:要与区域设置进行即时转换,您可以使用<cwchar>中的函数,例如:

ostream& operator<< (ostream& os, wchar_t wc) {
std::mbstate_t state{};
std::string mb(MB_CUR_MAX, '');
size_t ret = std::wcrtomb(&mb[0], wc, &state);
if(ret == static_cast<std::size_t>(-1))
deal_with_the_error();
return os << mb;
}

不要忘记将区域设置设置为系统默认值:

std::locale::global(std::locale(""));
std::cout << L'ŭ';