问题引入

考虑这样的一段代码:

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;void aligned_string() {string cstr1 = "中文", cstr2 = "对齐";string estr1 = "English", estr2 = "Alignment";cout << setw(20) << left << cstr1 << cstr2 << endl;cout << setw(20) << left << estr1 << estr2 << endl;
}int main() {aligned_string();
}

在默认的windows中文环境下(源代码文件和控制台的编码都是936,即一种GBK),setw()函数在中英文混合的场景下可以正常工作。


但是在unix环境下(默认使用UTF-8作为源代码和控制台的编码),setw()函数在中英文混合的场景下并不能正常工作。

产生原因

  • setw()函数的特性
    setw()函数中传入的参数,作为最终约定的“宽度”,并不是字符数,而是字节数。中英文在不同的编码方式下,有着不同的编码方式,每个字符所对应的字节数也不尽相同。

  • 编码方式
    Windows环境下的GBK和unix环境下的UTF-8对于英文字符均使用相同的单字节的编码方式(即ASCII),而对于中文字符的编码处理并不相同:

    • GBK:使用定长的双字符编码。因此由于等宽字体中,中文字符的宽度是英文字符的两倍,同时字节也是两倍,所以最终得到了正常的打印效果。
    • UTF-8:使用变长的字符编码。

使用以下的函数来按照小端序打印字符串"中文"

void print_string_bytes(string str) {for (int i = 0; i < str.size(); ++i)cout << hex << (unsigned)(unsigned char)str[i] << " ";cout << endl;
}

Windows平台的输出如下:


与在线平台的转换结果相同


Unix平台的输出如下:


和使用在线平台进行UTF-8转换的结果相同

解决方法

根据上面的分析可以得出结论:unix平台下setw()对于中文字符处理的问题在于变长字符编码。因此只要将字符串转换为定长字符编码(比如说GBK),之后计算两者之间的差值修改setw()的参数即可。

使用以下函数计算两种编码方式之间字节数量的差值:

#include <codecvt>
#include <locale>class chs_codecvt : public std::codecvt_byname<wchar_t, char, std::mbstate_t> {public:chs_codecvt() : codecvt_byname("zh_CN.GBK") {}
};int encoding_diff(string str) {wstring_convert<codecvt_utf8<wchar_t>> cv1;wstring wstr = cv1.from_bytes(str);wstring_convert<chs_codecvt> cv2;return str.size() - cv2.to_bytes(wstr).size();
}

其中codecvt_byname的构造函数是protected的,因此需要自定义一个转换器类,继承codecvt_byname

需要说明的是,在Linux环境下需要进行locale-gen,编辑/etc/locale.gen,删除zh_CN.GBK前面的注释符号,并执行locale-gen命令。

最终将打印函数修改如下:

void aligned_string() {string cstr1 = "中文", cstr2 = "对齐";string estr1 = "English", estr2 = "Alignment";string cestr1 = "中文English", cestr2 = "对齐Alignment";cout << setw(20 + encoding_diff(cstr1)) << left << cstr1 << cstr2 << endl;cout << setw(20 + encoding_diff(estr1)) << left << estr1 << estr2 << endl;cout << setw(20 + encoding_diff(cestr1)) << left << cestr1 << cestr2 << endl;
}

打印效果如下:

c++ 中文字符的 setw 格式化打印问题相关推荐

  1. c语言打印字符的函数参数,C语言格式化打印函数vsnprintf()的实现

    Linux内核的格式化打印函数是printk(),它与printf()函数是类似的,都是根据格式字符串把可变参数列表转化成字符序列,然后输出到控制台. printf()是打印到标准输出stdout. ...

  2. php调试代码时var_dump( )打印中文字符时出现乱码解决方案

    php调试代码时var_dump( )打印中文字符时出现乱码解决方案 参考文章: (1)php调试代码时var_dump( )打印中文字符时出现乱码解决方案 (2)https://www.cnblog ...

  3. 打印出所有的中文字符

    2019独角兽企业重金招聘Python工程师标准>>> 尝试打出所有的中文字符,中文字符的16进制范围是[u4e00-u9fa5]. public static String toS ...

  4. c++ 把数字和中文字符分开_C语言中的字符常量与变量

    字符常量与变量   在这一节中,我们来讨论字符与字符串. 1. 字符常量   如果我想在屏幕上打印"HelloWorld".应该怎样做呢?大家应该很熟悉这个代码了. #includ ...

  5. java中文字符怎么保证出现正确_JAVA中文字符编码问题详解

    JAVA中文字符编码问题详解 JAVA的中文字符乱码问题一直很让人头疼.特别是在WEB应用中.网上的分析文章和解决方案都很多,但总是针对某些特定情况的.很多次遇到乱码问题后,经过极为辛苦的调试和搜索资 ...

  6. C语言中的格式化打印printf/sprintf以及嵌入式printf重定向进行DEBUG

    一.printf描述 在C语言中,打印函数主要包括printf/sprintf/fprintf/snprintf等等,目的是将"给定的内容"按照"指定的格式"输 ...

  7. (best!)JAVA中文字符编码问题详解

    转载自:http://blog.csdn.net/youyue/article/details/4580402 JAVA中文字符编码问题详解 JAVA的中文字符乱码问题一直很让人头疼.特别是在WEB应 ...

  8. c语言中文网_在C语言中使用中文字符

    大部分C语言教材对中文字符的处理讳莫如深,甚至只字不提,导致很多初学者认为C语言只能处理英文,而不支持中文.其实C语言是一门全球化的编程语言,它支持世界上任何一个国家的语言文化,包括中文.日语.韩语等 ...

  9. python对浮点类型的数据进行格式化_(自用)Python Log2 数据类型、字符编码、格式化...

    数据类型 1.整数 十六进制可以使用0x+数字0-9(字母a-f). 2.浮点数 一般使用科学计数法,用e代替10,比如1.2e5,为1.2×10^5. 3.字符串 可以使用单引号' ',或者双引号& ...

  10. python 字符编码、格式化

      数据类型-布尔值 一个布尔值只有True.False两种值,要么是True,要么是False 布尔值可以用and.or和not运算 空值是Python里一个特殊的值,用None表示 Python对 ...

最新文章

  1. 从0到1,苏宁API网关的演进之路
  2. MySQL事务的特性
  3. Pycharm连接远程服务器进行代码调试开发
  4. spring boot整合mybatis步骤
  5. CentOS 7.6 安装 Maven 3.6.3
  6. Istio 网关中的 Gateway 和 VirtualService 配置深度解析
  7. 学习xss的一些记录(一)
  8. OAuth2.0_授权服务配置_授权码模式_Spring Security OAuth2.0认证授权---springcloud工作笔记144
  9. 亚马逊被爆内部员工卖数据改差评,中国区尤为严重!
  10. java实现rabbitmq任务模型(work queues), 生产者 消费者 消息队列 能者多劳
  11. 二元函数可导与可微的关系_视频教学:期末试卷解析之多元函数基本概念及相互关系讨论...
  12. Ubuntu18.04 如何解决编译objective-c出现undefined reference to objc_get_class
  13. d盘不见了 计算机打不开,D盘不见了怎么找回 电脑D盘没了解决方法
  14. 自适应YouTube视频嵌入
  15. cass坡度土方计算案例_四面放坡且坡度不同的工程土方,CASS怎么算?
  16. 不把鸡蛋放在一个篮子里面
  17. 语音识别(ASR)论文优选:关注语音识别系统Fairness问题Towards Measuring Fairness in Speech Recognition
  18. 好记性不如烂笔头The palest ink is better than the best memory
  19. Proxyee-down 3.x的下载与安装
  20. 工程流体力学笔记暂记16(欧拉积分和伯努利积分)

热门文章

  1. ubantu 14.04重置密码
  2. python数字转拼音输出_python 小程序:转换阿拉伯数字到拼音
  3. PHP 之建行龙支付-被扫(商家扫码客户二维码),扫码枪使用
  4. 阿拉伯数字金额转换为汉语大写
  5. Stored Outline
  6. 深度学习——汉字识别
  7. 【视频插帧】XVFI: eXtreme Video Frame Interpolation
  8. laravel文档工具
  9. 人工智能专业志愿该如何填报?
  10. 用java计算_用Java写的计算器