不论是客户端还是桌面端开发,相信总会遇到乱码问题。由于它太常见了,一般在网上随便一搜就能找到解决办法。无非是统一编码方式、转码等。但要想搞懂这个问题的根本原因,就需要对计算机存储字符的方式进行一番了解了。

字符集和字符编码

首先了解下什么是字符集和字符编码。字符集顾名思义就是现实世界中用到的符号集合,像英文字母、标点符号、汉字等等。而计算机是二进制的世界,不像人可以识别这么多字符,它只认识0和1。如何将现实中的符号用0和1来表示,就是字符编码所要解决的事情。

历史

关于如何在计算机中存储和表示现实世界中的符号,经历了如下几个阶段:

字符集和字符编码总结 - 图1

1. ASCII码

早期计算机刚诞生时,人们并没有想到它以后会发展这么快。当时只需要区分大小写英文字母、一些标点符号、数字和控制字符(非打印字符,用于控制打印机换行等)等即可,加起来也不到100个,用一个7位的二进制数就可就可以囊括了,因此ANSI组织制定了ASCII编码规范,每个字符对应一个固定的8位二进制数(最高位用于奇偶校验),也就是一个字节。
ASCII字符集由95个可打印字符(0x20-0x7E)和33个控制字符(0x00-0x19,0x7F)组成,编解码规则非常简单,就是直接查表匹配。

2.OEM和汉字编码

随着计算机的普及,人们很快发现ASCII字符包含的一百来个符号不够用了,由于ASCII码最高位并没有充分利用起来,因此人们打起了这一位的主意,将最高位利用起来,最多就可以包含2^8个字符,由于很多人都想到了这一点并付诸实践,导致同时出现了很多扩展字符集,互不兼容。
在中国,更麻烦的事情是汉字好几千个,一个字节装不下了。于是出现了多字节编码规范,像GBK、GB2312等,将一个汉字用2个字节来表示。

3.ANSI标准化

事情发展到这一阶段,不同字符集之间互不兼容,因此ANSI制定了规范,规定了在不同语言环境下采用的字符集,比如在中国采用GBK,美国默认采用ASCII等。

4.Unicode

ANSI只是指定了不同环境下采用哪种字符编码,本身并不是一个字符集。那么如果有一种字符集将世界上所有的符号都包含进来,不就可以真正的统一了吗,Unicode勇敢的做了这个尝试。它将世界上所有的符号都编上号码,并尽可能的兼容ANSI标准。例如U+0041表示英语的大写字母A,U+4E25表示汉字严。

Unicode的设计及实现

上述ASCII、GBK等既是字符集,又是字符编码规范,并没有进行区分,这样并不利于进行扩充。 Unicode只是一个字符集,它并没有规定具体的编码规范。对应的编码规范常见的有UTF-8、UTF-16。

  • UTF-16 : 标准的Unicode称为UTF-16(UCS Transformation System)。这种编码方式由于采用两个字节表示一个字符,所以与ASCII码不兼容
  • UTF-8 : 为了双字节的unicode可在单字节系统正确传输,出现了UTF-8。通过UTF-8编码的字节长短不同,0-127范围内的字符被编成1个字节,0080-07ff的字符被编成2个字节,0800-ffff的字符被编成3个字节…

参考资料