字符串的秘密(1) char 与 字符编码

408 阅读5分钟

这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战

我们每天都会用的UTF-8,UTF-16, GB2312,ASCII为什么会有这么多编码方式?为什么一个英文字母是一个byte,而中文就要是2个或者更多byte?同一个字符使用不同编码的结果一样么?为什么会有乱码?

如果不搞懂这些问题,那你在操作字符串的时候,肯定会踩不少坑。

基础知识

char是character的缩写,是字符的意思,就是我们平常写字用到的字符以及标点符号;

charset是character set的缩写,即字符集。我们常提到的Unicode,ASCII都是字符集。这些字符集中,通过不同的编码方式,将这些字符转换成计算机能识别和存储的二进制编码,而转换方式就是字符编码encoding。

每种字符集都有不同的编码方式:我们提到的UTF-8,UTF-16,UTF-32都是unicode字符集的编码方式。在早期,字符集和编码方式是一一对应的,但随着编程语言的发展,为了适应不同的开发和应用场景,同一个字符集有了多种的编码方式:

image.png

所以我们在HTML中经常写的<meta charset="utf-8">,其实并不准确,应该是encoding="utf-8".

谜之乱码?

乱码的产生,是因为编码方式和字符集的不匹配的导致:

  • ASCII码作为早期的字符集和编码,只支持拉丁字符和符号,使用1byte即8bit来表示一个char,最多只能支持256个char,但实际只用了128个,允许开发者自行拓展,目前用的比较多的是ISO-8859-1。

  • 我国的GB2312编码解决的就是计算机对中文字符的输入输出,规定用2个byte对应一个字符,并向下兼容ASCII;但世界上语言文字系统太多,当两套编码系统不兼容的时候,就会出现鸡同鸭讲,按照系统A的编码方式的字符,在系统B中就会得到错的字符,或者是“乱码”。

image.png

Unicode和码点

为了解决编码方式不兼容的问题,实现全世界字符的“大一统”,ISO提出了UNICODE字符集,来收录世界上大部分char,建立一个所有charset的并集。

image.png

这是从unicode官网上截的图,他们的目标就是:无论什么平台,无论什么程序,无论什么语言,Unicode都为每一个字符提供一个唯一的编号。

这就是Unicode的核心,这个唯一编号,我们称之为“码点” Code Point

  • 码点的编号从U+0000到U+10FFFF, u是指unicode,共支持1,114,112个编号;
  • 为了更好地管理unicode,把所有的码点可以平均分为17组,每组65536个编号,我们把这17组也成为17个“plane"平面,第一个平面就是plain0;
  • plain0也称为BMP(Basic Multilingual Plane 基本多语言平面),码点范围是 U+0000 ~ U+FFFF。BMP包含的是各种语言中日常用到的绝大部分字符。后续的 16 个平面称为 SP(Supplementary Planes补充平面),包括SMP,SIP等,如下图所示:

image.png

编码方式

编码方式,是将码点code point按照一定规则转换成二进制的过程。

Unicode字符集使用UTF编码方式(Unicode Transformation Format, Unicode转换格式),包括UTF-8, UTF-16, UTF-32,三种编码均能表示从 U+0000 ~ U+10FFFF 的所有字符。我们先来看一下码点和编码方式的对应关系:

image.png

utf-8: 最常用的编码方式,可变长度,1到4个字节对应一个字符。转换方式是将码点对应的二进制数字进行如下分拆与组合:

image.png

utf-16:同时结合了定长和变长两种编码方法的特点,基本平面的字符占用 2 个字节,辅助平面的字符占用 4 个字节。

utf-32: 固定4字节,定长。转换最简单,直接在码点前面垫 0 垫够 4 字节就行。最大缺点是占用空间太大。

举个UTF-8字符转换的例子,比如我们定义一个char=‘你’, 它在Unicode中的码点是U+4F60,那么4F60对应的二进制是0100111101100000, 按照转化规则,需要按照4-6-6进行分拆并组合:

1110(0100) 10(111101) 10(100000),对应的16位数字:E4 BD A0,需要3byte来表示。

到这里,我们就明白了为什么不同char对应的byte数会不一样。

以上,感谢阅读,如有不准确和错误之处请留言指正,我会立即修正,感谢!




总结不易,请勿私自转载,否则别怪老大爷不客气

欢迎喜欢技术的小伙伴和我交流,微信1296386616

参考资料:

《what is Unicode》 Unicode Consortium www.unicode.org/standard/Wh…

《字符集与编码(四)——Unicode》 肖国栋 xiaogd.net/md/%e5%ad%9…

<彻底弄懂Unicode编码> Li Yucang liyucang-git.github.io/2019/06/17/…