为什么要关心字符编码?
有时我们浏览网页,或者使用 Windows 自带的记事本查看包含非基础拉丁字符的文件时,会看到类似的现象:
「天呐,文字内容看不懂,我打开是什么!」
「内容没法正常显示,多半是字符编码的锅。」
此现象称为「乱码」,日语称为文字化け,英语称为 Mojibake(音译自日语)。「乱码」改变的不仅仅是字形,连字符个数都将受影响;不光会大大影响阅读,而且会在 web 上使你生产的内容无法被搜索引擎识别。无论作为阅览者,还是生产者,乱码都是我们需要避免的问题。
什么是字符编码
首先,还要先提另一个概念:「字符集」。
「字符集」和「字符编码」有什么关系吗?
Charset is the set of characters you can use.
Encoding is the way these characters are store into memory.
摘自于 Stackoverflow.
「字符集」就是字符的集合,而「字符编码」是字符如何存储在计算机中的方式。举个例子,Unicode 就是「字符集」,而 UTF-8 则是「字符编码」。
有很多种不同的字符编码,不同的字符编码定义字符的方式也不一样。例如每台计算机都带有的 ASCII 编码,大陆常用的 GB2312, GB18030、台湾常用的 BIG5,以及未来趋势 UTF-8。
UTF-8
最常见的 ASCII 采用 7 位表示一个字符,共课表达 128 个字符,仅能显示基本拉丁字符,对于其他语言完全不够,更加别提字符数量巨大的 CJK 地区字符。不管是大陆的 GB18030 或 台湾的 BIG5,虽然能满足中文使用,依然面临诸多不便,例如如果海外的计算机不内置这些编码,则无法阅览相关内容。所以,企图包含人类所有字符的字符集出现了:Unicode。目前(2017-03-06)最新版本为 9.0。
如此庞大的字符,如何为其编码?Unicode 定制时,计算机存储器容量也大大增长了。Unicode 采用 16 位表示一个字符,对于 ASCII 与其扩展保持不变,剩下高位用 0 填满。其他语言重新编码。然后新的问题来了:
原本拉丁字符只要占 1 个字节,现在却要花更多的空间。
UTF-8 还好的解决了这个问题——采用变长编码的方式。UTF-8 使用 1~4 个字节表示一个字符。这里引用他人的描述:
- 如果一个字节的第一位为 0,那么代表当前字符为单字节字符,占用一个字节的空间。0 之后的所有部分(7 个 bit)代表在 Unicode 中的序号。
- 如果一个字节以 110 开头,那么代表当前字符为双字节字符,占用 2 个字节的空间。110 之后的所有部分(5 个 bit)加上后一个字节的除 10 外的部分(6 个 bit)代表在 Unicode 中的序号。且第二个字节以 10 开头
- 如果一个字节以 1110 开头,那么代表当前字符为三字节字符,占用 2 个字节的空间。110 之后的所有部分(5 个 bit)加上后两个字节的除 10 外的部分(12 个 bit)代表在 Unicode 中的序号。且第二、第三个字节以 10 开头
- 如果一个字节以 10 开头,那么代表当前字节为多字节字符的第二个字节。10 之后的所有部分(6 个 bit)和之前的部分一同组成在 Unicode 中的序号。
如何查找某个字符的编码?
macOS 自带的表情与符号可以找到字符在不同编码方式下的码位。