前言
相信不少同学在开发的过程中都会碰到过字符乱码的问题。
文件打开的字符编码格式不对,或者返参解析的编码格式不一致都有可能造成乱码问题。
而我们熟悉且常用的字符编码格式有这么几个: ASCII、GBK、Unicode、UTF8
但是我们真的了解这些字符编码?为什么会有这么多种类型字符编码,统一用一种不就好了吗?他们之间又有什么联系?(灵魂三连问)
而肥壕也是只知其然,而不知其所以然,所以决定一探究竟。
正文
ASCII
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可以部分支持其他西欧语言,并等同于国际标准**[ISO/IEC 646]**。
简单说,就是把英文字母、数字符号 与 二进制之间做了一套统一的规定。ASCII 一共定义了 128 个字符的编码,用一个字节表示,但只占用了一个字节的后 7 位,最高位统一规定为 0。
GB
国家标准代码,简称国标码,是中华人民共和国的中文常用汉字编码集,亦为新加坡采用。
目前中华人民共和国官方强制使用
GB 18030–2005
标准,但GB 2312–80
仍然在部分领域被使用。强制标准冠以
GB
。推荐标准冠以GB/T
。国家标准化指导性技术文件冠以GB/Z
。
GB2312:(又称 GB1)是第一个修订的汉字编码字符集,每个汉字占两字节,收录了 6,763 个汉字。
GBK:由于中文博大精深,6763个大小无法覆盖所需的汉字,于是 GBK 兼容 GB2312 和 ASCII 的前提下扩展到了 21,003 个汉字。
GB18030:然而两万多字也没法满足咱们汉字的需求,两字节最多表示 65536个汉字,因此 GB18030 决定多出来的汉字使用四字节来表示,于是又在 GBK 的基础上扩展到了 70,244 个汉字。
Unicode
Unicode,中文又称万国码、国际码、统一码、单一码,是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。
很显然,不同国家都有各自的语言和编码,甚至对同一个文件如果写入和打开的编码格式不一致,也会导致乱码的出现。为了解决这个问题,雄心勃勃的 Unicode 就此出现,誓要把世界上所有的符号都统一编码规范。
Unicode 目前还不断在扩增,目前最新的版本为2020年3月公布的 13.0.0 ,已经收录超过13万个字符。
但是有这么一个问题,Unicode 只是一个字符集,定义了符号的二进制代码,但是没有规定存储的格式。所以就会存在两个问题:
- 如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示 3 个符号呢?
- 我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用 3 个或 4 个字节表示,那么每个英文字母前都必然有 2- 3个字节是
0
,这对于存储来说是极大的浪费,文本文件的大小会因此大出 2 - 3倍,这是无法接受的。
为了解决这存储格式不一致的问题,我们就需要有一个统一的格式,而下面的 UTF-8 就是其中的一个实现方式。
UTF-8
UTF(Unicode Transformation Format,称为Unicode转换格式)
UTF-8(8-bit Unicode Transformation Format)是一种针对 Unicode 的可变长度字符编码 ,也是一种前缀码 。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码,属于Unicode 标准的一部分。
UTF-8 是 Unicode 的实现方式之一,也是目前互联网上使用最广的一种实现方式。它的最大特点是可变长度编码,根据不同的符号使用 1-4 字节字符来表示。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为
0
,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。2)对于
n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。依次从后往前填充。
代码范围 | UTF-8 | 注释 |
---|---|---|
000000 - 00007F | 0xxxxxxx(00-7F) | 128个 |
000080 - 0007FF | 110xxxxx(C0-DF) 10yyyyyy(80-BF) | 1920个 |
000800 - 00D7FF 00E000 - 00FFFF | 1110xxxx(E0-EF) 10yyyyyy 10zzzzzz | 61440个 |
010000 - 10FFFF | 11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz | 1048576个 |
如果能够大概理解上面的描述和表格的规则,解读 UTF-8 还是应该比较容易的。如果字符的第一位是 0 ,就说明这个单字节字符;如果第一位是 1 的话,就看最高位连续有多少个 1 就是多少个字节了。
举个例子:
字符 A
,ASCII 二进制是 01000001
,Unicode 二进制是 00000000 01000001
十六进制是 41
,根据上表规则可知在第一个范围内,所以是单字节字符对应的 UTF-8 的编码也很容易得出来 01000001
。
字符 中
,Unicode 二进制是 01001110 00101101
十六进制是 9b2d
十进制是 39725
,对应上表可知在第三个范围内,所以需要三个字节表示,我们只要往模板 1110xxxx(E0-EF) 10yyyyyy 10zzzzzz
将 unicode 的字符依次往后填充即可 11100100 10111000 10101101
当然还有其他实现方式比如 UTF-16(使用 2 或 4 字节表示)、UTF-32(使用 4 字节表示),这里就不仔细详述,大概了解一下就好了。
参考资料:
普通的改变,将改变普通
我是宅小年,一个在互联网低调前行的小青年
关注公众号「宅小年」,个人博客 📖 edisonz.cn,阅读更多分享文章