一张图看懂字符集和编码

背景

需要写一个汉字转拼音的程序,参考了网上的代码,没一个能正常工作的。后来发现是字符集和编码的锅,下面做一个总结。

字符编码的由来

1.电脑上的字符本质上是像素点组成的图案,最开始IBM个人电脑普及的时候,电脑程序附带了一张字符集,里面是各种字符的显示图案,电脑要显示一个字符就去找对应位置序号的图案,然后原样显示出来,简单讲就是一个 查表的过程

2.刚开始只有美国人有电脑,于是ANSI字符集诞生了,后来欧洲也开始普及了,需要显示意大利语,法文,ANSI字符集里面的127个字符是不够用的,于是需要扩充,刚开始7个Bit就能组合出所有的英文字符和符号,于是ISO组织扩展了第8位,这样就有了 Latin-1 字符集,也叫 ISO-8859-1,就能表示出255个字符组合,显示意大利语,法文不再是难题;最后轮到亚洲国家,尤其是发展中的中国,庞大的汉字体系,还分简体,繁体,藏文,这把美国人吓尿了. 于是就有了后来的 GB2312,GBK,BIG5(繁体字),GB18030,UNICODE, UTF8, 这样一来字符数越多,每个字符占用的位数就要相应增加. 下面是各种字符集的简要说明.

字符集对比

字符集简介每个字符占用位宽
ANSI收入英文字母,数字和符号共127个单字节,实际只用了低7位,最高位为0
ISO-8859-1收入英文字母,数字和符号共256个,兼容 ANSI单字节
GB2312收入简体汉字 6763 个和非汉字图形字符 682双字节
GBK23940 个码位,收录了 21003 个简体汉字,兼容 GB2312双字节
GB18030收入简体汉字,包括少数民族文字 共计 70,244多字节
BIG5收入繁体汉字 13,060双字节
UTF-8用1到4个字节编码Unicode字符多字节,省存储空间,易传输
UTF-16以1个或者2个16位长编码UNICODE字符1个双字节,或者2个双字节
UTF-32对每一个Unicode码位使用恰好32Bit四个字节
UNICODE跨语种解决方案,可以容纳世界上所有的文字符号双字节

注: 所谓 码位 就是字符在对应字符集所处位置(序号).

编译器对中文的测试

    wxString str1 = wxT("中国人");
    std::wstring str2= L"中国人";
    
    std::cout<<"str1 = "<<str1<<std::endl;
    std::cout<<"str2 = "<<str2<<std::endl;
    std::wcout<<"str2_ ="<<str2<<std::endl;
codeblocksVS2018
编译器G++MS
编译器默认编码UTF8UNICODE
源代码文件格式UTF8UTF8
输出结果正常正常

几个有用的函数

/**
 * @target : 多字节字符串转十六进制,支持中英文混合
 * @param str : 要转换成十六进制的字符串
 * @param separator : 十六进制字符串间的分隔符
 * @return : 16进制字符串
 */
std::string stringToHex(std::string str, std::string separator)
{
	const std::string hex = "0123456789ABCDEF";
	std::stringstream ss;
	for (std::string::size_type i = 0; i<str.size(); ++i)
	{
		ss << hex[(unsigned char)str[i] >> 4] 
		   << hex[(unsigned char)str[i] & 0x0f]
		   << separator;
	}
	return ss.str();
}

/**
 * @target : Unicode宽字符串转十六进制,支持中英文混合
 * @param str: 要转换成十六进制的Unicode字符串
 * @param separator: 十六进制字符串间的分隔符
 * @return : 16进制字符串
 */
std::string wstringToHex(std::wstring str, std::string separator)
{
	const std::string hex = "0123456789ABCDEF";
	std::stringstream ss;
	for (std::wstring::size_type i = 0; i < str.size(); ++i)
	{
        ss << hex[(uint16_t)str[i] >> 12 & 0x0f]
           << hex[(uint16_t)str[i] >> 8 & 0x0f]
           << separator
		   << hex[(uint16_t)str[i] >> 4 & 0x0f]
	       << hex[(uint16_t)str[i] & 0x0f]
	       << separator;
	}
	return ss.str();
}

测试

— code blocks —

  源代码
  wxCSConv gbkConv(wxFONTENCODING_CP936);
  std::string str_gbk(gbkConv.cWX2MB(_T("z国"))); //gbk格式
  std::string str_utf8("z国"); // utf8格式
  std::wstring str_unicode(gbkConv.cWX2WC(_T("z国")));// unicode格式

  std::cout<<"[str_gbk         ] = "<<str_gbk<<std::endl;
  std::cout<<"[str_utf8        ] = "<<str_utf8<<std::endl;
  std::cout<<"[str_unicode     ] = "<<str_unicode<<std::endl;
  std::cout<<"[str_gbk size    ] = "<<str_gbk.size() <<std::endl;
  std::cout<<"[str_utf8 size   ] = "<<str_utf8.size()<<std::endl;
  std::cout<<"[str_unicode size] = "<<str_unicode.size()<<std::endl;
  std::cout<<"[str_gbk HEX     ] = "<<stringToHex(str_gbk)<<std::endl;
  std::cout<<"[str_utf8 HEX    ] = "<<stringToHex(str_utf8)<<std::endl;
  std::wcout<<"[str_unicode HEX ] = "<<wstringToHex(str_unicode)<<std::endl;
输出结果
[debug][str_gbk         ] = z国
[debug][str_utf8        ] = z鍥nicode     ] = z国
[debug][str_gbk size    ] = 3
[debug][str_utf8 size   ] = 4
[debug][str_unicode size] = 2
[debug][str_gbk HEX     ] = 7A B9 FA 
[debug][str_utf8 HEX    ] = 7A E5 9B BD 
[debug][str_unicode HEX ] = 00 7A 56 FD 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值