![image-20210226175522617](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226175522.png)
# 字符集和字符编码
**字符集(CCS: Coded Character Set):**
就是一个表格,表示每个字符对应数字(通常用16进制表示),比如[unicode](https://www.unicode.org/charts/PDF/U0000.pdf)字符集中,数字1对应的就是`U+00031`,字母a对应的就是`U+00061`。
![image-20210226175533944](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226175533.png)
**字符编码(CEF:Character Encoding Form):**
因为计算机只认识`0`和`1`,所以计算机在存储`字母a`(`U+00031`)的时候,不能直接存储。所以就需要编码将`字母a`转换成`01`表示形式。对于`unicode`字符,`utf8`就是它的编码方案(如何`utf8`转换成`01`表示下文介绍)。
**字符:**
字符简单理解就是人类能(容易)看懂得符号。
比如对于汉字`严`,机器存储的是`11100100 10111000 10100101`,人类根本看不懂。转换成`unicode`表示方法是`U+4E25`,依然看不懂。
人类只能看懂`严`这个字符,三者之间的关系如下:
![image-20210226175546407](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226175546.png)
字符串到保存文件过程如下:
![image-20210226175558858](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226175558.png)
# UTF-8编码
`严`这个字的`unicode`码是`U+4E25`(对应的二进制数字是`100111000100101`),而`utf8`编码之后是`11100100 10111000 10100101`,是不是很奇怪?两个二进制完全不一样,是因为`utf8`有一套编码规则。
![image-20210226175616715](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226175616.png)
## UTF-8编码规则
`utf8` 最大的一个特点,就是它是一种`可变长`的编码方式。它可以使用`1~4`个字节表示一个符号,根据不同的符号而变化字节长度。
`utf8` 的编码规则很简单,只有二条:
- 对于单字节的符号,字节的第一位设为`0`,后面7位为这个符号的 Unicode 码。因此对于英语字母,`utf8` 编码和 `ASCII` 码是相同的。
- 对于`n`字节的符号(`n > 1`),第一个字节的前`n`位都设为`1`,第`n + 1`位设为`0`,后面字节的前两位一律设为`10`。剩下的没有提及的二进制位,全部为这个符号的 `Unicode` 码。
下表总结了编码规则,字母`x`表示可用编码的位。
```
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
```
`严`字的`Unicode`编码是`4E25`处于`0000 0800 - 0000 FFFF`这个范围里面,所以需要三个字节表示。
![](https://bbk-images.oss-cn-shanghai.aliyuncs.com/typora/20210226212135.png)
哇塞,原来是这样
# utf8和utf8mb4
`utf8mb4`只是`mysql`特有的概念,原因是`mysql`在`5.5.3`之前,`Unicode`收录的字符还不是很多,(最大)3个字节足够存储,所以那时的`mysql`把`utf8`(alias of "`utf8mb3`")存储也设计为3字节存储。后来`Unicode`收录的字符更多了,扩张到4字节了(比如表情😁)。
MySQL也在`5.5.3`版本之后增加了这个`utf8mb4`的编码,`mb4`就是`most bytes 4`的意思,专门用来兼容四字节的`Unicode`。
MySQL官方网站也解释了`utf8mb3`和`utf8mb4`之间的关系。
[https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb4.html](https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb4.html)
[https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb3.html](https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-utf8mb3.html)
# 总结
- `Unicode`是字符集,是符合和码点的映射表
- `utf8`是`Unicode`的一种最常见的字符编码方式(还有`utf16`、`utf32`)
- `mysql`中`utf8`实际上是`utf8mb3`(最大存储3字节),`utf8mb4`最大可以存储4字节(大部分表情都要占用4字节,所以需要选择`utf8mb4`)
有疑问加站长微信联系(非本文作者)