5分钟,搞清 Unicode 与 UTF-8 的区别
Unicode 是什么?
Unicode,官方中文名称“统一码”。通常大家谈到的 Unicode 一般指字符集的意思,但 Unicode 标准实际涵盖两个方面的内容:
- Unicode 字符集
- Unicode 编码
Unicode 字符集
Unicode 为每个字符提供一个唯一数字(码点 code point),记为“U+xxxx”,其中xxxx是码位转换成16进制后的结果。
字符->码位的集合即 Unicode 字符集,也称作通用字符集(英语:Universal Character Set, UCS)。可在这里查询字符对应的码位。
例如「中」的码点是 20013,记作 U+4E2D(20013 的十六进制为 0x4E2D)。它的二进制为100111000101101
,这至少需要2个字节才能存储到计算机中。那为什么我们看到的是一个个字符,而不是二进制数呢?
Unicode 编码
Unicode 字符集规定了字符对应的唯一码点,但在实际的传输、存储过程中,为了兼顾各系统平台的差异、节省空间,需要对字符集进行编码——将对应的码点转换成另一种格式,即Unicode转换格式(Unicode Transformation Format,简称 UTF)。
Unicode 编码规则决定了码点如何在文件中显示,我们熟知的UTF-8
UTF-16
就是编码规则的不同版本。
UTF-8 编码过程
UTF-8 是一种针对 Unicode 的可变长度字符编码,根据码点的大小,将其编码为 1 到 4 个字节,具体规则如下:
U+0000 - U+007F: 0xxxxxxx (1个字节)
U+0080 - U+07FF: 110xxxxx 10xxxxxx (2个字节)
U+0800 - U+FFFF: 1110xxxx 10xxxxxx 10xxxxxx (3个字节)
U+10000 - U+10FFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (4个字节)
「中」的码点为U+4E2D,由上表可知,它属于第三行,被编码成三个字节:
4 E 2 D
0100 1110 0010 1101
-----------------------------
1110xxxx 10xxxxxx 10xxxxxx // 上表第三行
____0100 __111000 __101101 // 将 4E2D 的二进制带入上面的格式中
-----------------------------
11100100 10111000 10101101
以上就是字符「中」经过 UTF-8 编码后得到字节序列的过程,反之亦然。
Unicode 和 UTF-8 的区别
简单来说,Unicode 是【字符集】,UTF-8 是字符集的一种【编码规则】。但广义来讲,它们是包含关系,如下图:
+-----------------------------+
| Unicode |
| +-----------------------+ |
| | 通用字符集(UCS) | |
| +-----------------------+ |
| +------------------------+ |
| | UCS转换格式(UTF) | |
| | +-------------------+ | |
| | | UTF-8, UTF-16 ... | | |
| | +-------------------+ | |
| +------------------------+ |
| |
+-----------------------------+
补充
字节、字符、字符串
- 字节:计算机中存储数据的最小单元,一个8bit的二进制数,譬如0x01、0x45...
- 字符:人类使用的一个个文字符号,在计算机中通常用英文单引号包裹,譬如'中'、'A'、'%'、'。'...
- 字符串:多个字符 串联起来形成字符串,在计算机中通常用英文双引号包裹,譬如"中华人民共和国万岁"、"MAGA"...
字符以二进制数据形式存储在计算机中,我们在文件中看到的一个个字符,是根据某种编码规则转换后的结果。
字符串长度
同一个字符,在不同的编码规则下,它的长度也不一样。JavaScript 使用 UTF-16 编码,该编码使用 16 比特为1个编码单元来表示大部分常见的字符,使用两个代码单元表示不常用的字符。
'中'.length === 1 // true
'😀'.length === 2 // true
更进一步,我们用 rust 来检验这个规则:
fn main() {
let s1 = "中";
assert_eq!(s1.len_utf8(), 3);
assert_eq!(s1.len_utf16(), 1);
}
最后回答自己一个问题,1个汉字几个字节?