什么是字符编码,为什么要字符编码?
字符编码
Character Set(字符集)只是给所有的字符一个唯一编号,但是却没有规定如何存储。Unicode最常用的是用两个字节表示一个字符,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
Unicode和Ascii是一种编码方式
,通过UTF-8、UTF-16、UTF-32等存储方式
,将字符表示成程序中的数据,在存储和传输上节约空间,提高性能
UTF-8: 是「编码规则」
UTF是“Unicode Transformation Format”的缩写,可以翻译成Unicode字符集转换格式
,即怎样将Unicode定义的数字
转换成程序数据
。
例如,“汉字”对应的数字是0x6c49和0x5b57,而编码的程序数据是:
char data_utf8[] = {0xE6,0xB1,0x89,0xE5,0xAD,0x97}; //UTF-8编码
char16_t data_utf16[] = {0x6C49,0x5B57}; //UTF-16编码
char32_t data_utf32[] = {0x00006C49,0x00005B57}; //UTF-32编码
我们可以规定,一个字符使用四个字节存储,也就是 32 位,这样就能涵盖现有 Unicode 包含的所有字符,这种编码方式叫做 UTF-32(UTF 是 UCS Transformation Format 的缩写)。UTF-32 的规则虽然简单,但是缺陷也很明显很浪费空间
,假设使用 UTF-32 和 ASCII 分别对一个只有西文字母的文档编码,前者需要花费的空间是后者的四倍
(ASCII 每个字符只需要一个字节存储)。
在存储和网络传输中,通常使用更为节省空间的“变长编码方式” UTF-8。UTF-8是一套以 8 位为一个编码单位的可变长编码
。会将一个码位编码为1-6个字节,常用的英文字母被编码成1个字节
,汉字通常是3个字节
,只有很生僻的字符才会被编码成4-6个字节
。
UTF-8 的编码规则
UTF-8 的编码规则如下(U+ 后面的数字代表 Unicode 字符代码):
Unicode编码(十六进制) UTF-8 字节流(二进制)
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
可以看到,UTF-8 通过开头的标志位位数
实现了变长。对于单字节字符,只占用一个字节,实现了向下兼容 ASCII,并且能和 UTF-32 一样,包含 Unicode 中的所有字符,又能有效减少存储传输过程中占用的空间。
比如:一个编号为 65 的字符,只需要一个字节就可以存下,但是编号 40657 的字符需要两个字节的空间才可以装下,而更靠后的字符可能会需要三个甚至四个字节的空间。
Demo:将 Unicode 按照 UTF-8 编码为字节序列
汉字: 知
Unicode码: 30693
Unicode码的十六进制表示为: 0x77E5
根据utf-8的上表中的编码规则,「知」字的码位U+77E5属于第三行的范围:所以需要3个字节(byte)
7 7 E 5
0111 0111 1110 0101 二进制的 77E5
--------------------------
1110XXXX 10XXXXXX 10XXXXXX 模版(由77E5范围,取上表第三行)
0111 011111 100101 根据模板格式调整77E5二进制的结构
11100111 10011111 10100101 代入模版
E 7 9 F A 5 转化回16进制
这就是将 U+77E5 按照 UTF-8 编码为字节序列 E79FA5 的过程。反之亦然。