字符编码笔记

字符编码笔记

Scroll Down

前言

相信不少同学在开发的过程中都会碰到过字符乱码的问题。

文件打开的字符编码格式不对,或者返参解析的编码格式不一致都有可能造成乱码问题。

而我们熟悉且常用的字符编码格式有这么几个: ASCII、GBK、Unicode、UTF8

但是我们真的了解这些字符编码?为什么会有这么多种类型字符编码,统一用一种不就好了吗?他们之间又有什么联系?(灵魂三连问)

而肥壕也是只知其然,而不知其所以然,所以决定一探究竟。

正文

ASCII

ASCIIAmerican 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 只是一个字符集,定义了符号的二进制代码,但是没有规定存储的格式。所以就会存在两个问题:

  1. 如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示 3 个符号呢?
  2. 我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用 3 个或 4 个字节表示,那么每个英文字母前都必然有 2- 3个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出 2 - 3倍,这是无法接受的。

为了解决这存储格式不一致的问题,我们就需要有一个统一的格式,而下面的 UTF-8 就是其中的一个实现方式

UTF-8

UTF(Unicode Transformation Format,称为Unicode转换格式

UTF-88-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 - 00007F0xxxxxxx(00-7F)128个
000080 - 0007FF110xxxxx(C0-DF) 10yyyyyy(80-BF)1920个
000800 - 00D7FF
00E000 - 00FFFF
1110xxxx(E0-EF) 10yyyyyy 10zzzzzz61440个
010000 - 10FFFF11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz1048576个

如果能够大概理解上面的描述和表格的规则,解读 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 字节表示),这里就不仔细详述,大概了解一下就好了。

参考资料:

字符编码笔记:ASCII,Unicode 和 UTF-8

程序员必备:彻底弄懂常见的7种中文字符编码

普通的改变,将改变普通

我是宅小年,一个在互联网低调前行的小青年

关注公众号「宅小年」,个人博客 📖 edisonz.cn,阅读更多分享文章