iostreams - 将 `wchar_t` 或 `charXX_t` 值打印为字符
Posted
技术标签:
【中文标题】iostreams - 将 `wchar_t` 或 `charXX_t` 值打印为字符【英文标题】:iostreams - Print `wchar_t` or `charXX_t` value as a character 【发布时间】:2017-04-27 17:18:30 【问题描述】:如果您将 wchar_t
、char16_t
或 char32_t
值提供给窄 ostream,它将打印代码点的数值。
#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*
并打印为指针值,非窄字符串objects(@ 987654338@, u16string
, u32string
) 甚至无法编译。
所以,问题是:在狭窄的 ostream 上打印wchar_t
、char16_t
或 char32_t
值的最不可怕的方法是,作为字符,而不是作为代码点的数值?它应该正确地将在 ostream 的编码中可表示的 所有 个代码点转换为该编码,并在代码点不可表示时报告错误。 (例如,给定u'…'
和一个UTF-8 ostream,应该将三字节序列0xE2 0x80 0xA6 写入流;但给定u'â'
和一个KOI8-R ostream,应该报告错误。)
同样,如何在窄流上打印非窄 C 字符串或字符串对象,转换为输出编码?
如果这不能在 ISO C++11 中完成,我将采用特定于平台的答案。
(灵感来自this question。)
【问题讨论】:
简而言之,您必须 1) 使用宽 ostream,或 2) 自己将宽字符数据转换为窄编码(这可能是有损转换)。 ostream 无法为您进行转换。查看std::wstring_convert
,或使用ICONV 或ICU 之类的库。
【参考方案1】:
正如您所指出的,狭窄的 ostream 没有 operator<<(std::ostream&, const wchar_t)
。但是,如果您想使用该语法,您可以教 ostream
如何处理 wchar
s,以便选择该例程作为比需要先转换为整数的例程更好的重载。
如果您喜欢冒险:
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, '\0');
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'ŭ';
【讨论】:
这不会将值转换为窄输出编码。这是必不可少的,也是我不知道该怎么做的部分。 @zwol 如果宽字符在 ASCII 范围内则接受它并拒绝它,您还想如何转换它?然后,您需要具体,例如,删除重音或其他内容。 你的例子使用了一个'x'来传递这个(对于L'x'
,你需要对其他类型做同样的事情)所以我认为这就是你所追求的。跨度>
当窄输出编码为 UTF-8 时,应该将 L"…" 转换为三字节序列 0xE2 0x80 0xA6。
我认为很明显,我想要能够处理窄输出编码支持的所有个字符,而不仅仅是ASCII。以上是关于iostreams - 将 `wchar_t` 或 `charXX_t` 值打印为字符的主要内容,如果未能解决你的问题,请参考以下文章