首页 > 代码库 > 字符集和字符编码
字符集和字符编码
转自:http://cenalulu.github.io/linux/character-encoding/
字符集
简单地说字符集就规定了某个文字对应的二进制数字存放方式(编码)和某串二进制数值代表哪个文字(解码)的转换关系。
文字<---------->二进制数据字符串
编码集对应
字符集 | 16进制编码 | 对应的二进制数据 |
UTF-8 | 0xE5B18C | 111001011011000110001100 |
UTF-16 | 0x5C4C | 101110001001100 |
GBK | 0x8CC5 | 1000110011000101 |
字符编码
对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、字符编码(character encoding form)。
- 字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。
- 编码字符集,即用一个编码值
code point
来表示一个字符在字库中的位置。 - 字符编码,将编码字符集和实际存储数值之间的转换关系。一般来说都会直接将
code point
的值作为编码后的值直接存储。
例如在ASCII中A
在表中排第65位,而编码后A
的数值是0100 0001
也即十进制的65的二进制转换结果。
统一字库表的目的是为了能够涵盖世界上所有的字符,但实际使用过程中会发现真正用的上的字符相对整个字库表来说比例非常低。例如中文地区的程序几乎不会需要日语字符,而一些英语国家甚至简单的ASCII字库表就能满足基本需求。而如果把每个字符都用字库表中的序号来存储的话,每个字符就需要3个字节(这里以Unicode字库为例),这样对于原本用仅占一个字符的ASCII编码的英语地区国家显然是一个额外成本(存储体积是原来的三倍)。于是就出现了UTF-8这样的变长编码。在UTF-8编码中原本只需要一个字节的ASCII字符,仍然只占一个字节。而像中文及日语这样的复杂字符就需要2个到3个字节来存储。
UTF-8和Unicode的关系
Unicode就是上文中提到的编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。
UTF-8编码简介
为了更好的理解后面的实际应用,我们这里简单的介绍下UTF-8的编码实现方法。即UTF-8的物理存储和Unicode序号的转换关系。
UTF-8编码为变长编码。最小编码单位(code unit
)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。
- 如果一个字节的第一位为0,那么代表当前字符为单字节字符,占用一个字节的空间。0之后的所有部分(7个bit)代表在Unicode中的序号。
- 如果一个字节以110开头,那么代表当前字符为双字节字符,占用2个字节的空间。110之后的所有部分(7个bit)代表在Unicode中的序号。且第二个字节以10开头
- 如果一个字节以1110开头,那么代表当前字符为三字节字符,占用2个字节的空间。110之后的所有部分(7个bit)代表在Unicode中的序号。且第二、第三个字节以10开头
- 如果一个字节以10开头,那么代表当前字节为多字节字符的第二个字节。10之后的所有部分(6个bit)代表在Unicode中的序号。
具体每个字节的特征可见下表,其中x
代表序号部分,把各个字节中的所有x
部分拼接在一起就组成了在Unicode字库中的序号
为什么会出现乱码
简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集
字符集和字符编码