今天查阅一些编码相关的资料,看后有了一定的理解,整理了一下思路发上来,如有错误的地方,望指正。
1、什么是字符编码
1.1 字符编码涉及到的名词
(1)抽象字符集(Abstract character repertoire)
这个集合包含了当前系统支持的所有字符,比如“李”、“A”、“¥”等字符。只包含字符,不包含其他东西,如字体/大小等。
(2)编码字符集(Coded Character Set)
将[抽象字符集]中的每一个字符映射到一个坐标或者一个正整数上,这个映射的值称为码位(code point)。[抽象字符集]+[位码] = [编码字符集]。Unicode就是一个[编码字符集]。每个字符都有自己唯一的码位(类似人的身份证号),通过码位就可以找到对应的字符。
(3)字符编码方式(Character Encoding Form)
[编码字符集]与实际储存数值之间的转换方式(格式)。将[编码字符集]的码位转换成有限bit长度的整形值([码元]code units)的序列。
(4)字符编码方案(Character Encoding Scheme)
将[码元]映射到8位字节序列,以便编码后的数据文件储存或网络传输。例:见2.UFT-8编码。
1.2 为什么会有这么多[抽象字符集]
诞生顺序:ASCII --> 非ASCII --> Unicode --> UTF-8
(1) ASCII (American Standard Code for Information Interchange)
计算机刚出现时设计的编码,只包含英文字符。
(2) 非ASCII
随着计算机的普及,计算机必须要支持其他国家的语言,但ASCII只支持英文字符,所以只能新增其他的字符集,如汉字的GB2312、BIG5。
(3) Unicode
每个国家都有自己的字符集易导致混乱不统一,比如A文件在B国家是正常的,但是到C国家就显示乱码。所以就出现了Unicode,称为统一码、万国码,它包含了所有的字符,它为每种语言的每个字符都定了统一的、唯一的二进制编号,用以满足跨语言,跨平台的需求。
(4) UTF-8 (Unicode Transformation Format 8-bit)
a、由于Unicode字符集太大,里面很多字符在某些国家基本不会用到,且Unicode储存字符时需要至少2个字节以上的空间,很浪费资源。如A字符在ASCII中只占1个字节,但在ASCII最少占2个字节。所以就出现了UTF-8,UTF-8是Unicode的一种实现方式(UTF-8全称 在UTF-8编码中原本只需要一个字节的ASCII字符,仍然只占一个字节,而复杂字符就需要2个到6个字节来存储。
b、由于Unicode只规定了编码方式,未规定解码方式。如有一串2字节的二进制,是以1个字节为1个字符的方式解码还是2个字节为1个字符的方式。出现UTF-8编码后就可以用UTF-8的方式来解析这串二进制(例子:见 2、UFT-8编码)。
Unicode[编码]流程:Unicode(字符集-->对应的编号)-->二进制数储存。 //Unicode已做到
Unicode[解码]流程:解码显示<--Unicode(字符集<--对应的编号)<--二进制数储存 //以何种方式来[解码显示]?Unicode未规定,所以就出现了UTF-8
UTF-8解码:二进制数储存-->Unicode(对应的编号-->字符集)-->用UFT-8的编码方式来解码显示当前字符。 //同一个Unicode编号在不同编码(UTF-8/GB2312)的解码下获取到字符会不一样。
2、UFT-8编码
(1) 单字节的字符。[首字节]的第1位(bit)设为0,随后的7位是这个字符的Unicode码。如:0xxxxxxx
(2) N(N > 1)字节的字符。[首字节]:前N位都设为1,第N+1位设为0,其余的位为这个字符的Unicode码;
[非首字节]:前2位设为10,其余的位为这个字符的Unicode码;
如:0xxxxxxx 1字节的字符UFT-8二进制格式
110xxxxx 10xxxxxx 2字节的字符UFT-8二进制格式
1110xxxx 10xxxxxx 10xxxxxx 3字节的字符UFT-8二进制格式
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4字节的字符UFT-8二进制格式
记忆点:首字节的首位以0开头说明当前是单字节字符。首字节连续为1的位有几个,则当前字符就由几个字节组成。
例子1:
--------------------------------------------------------------------------------------------
字符 UFT-8编码的二进制 | UFT-8编码的十六进制
--------------------------------------------------------------------------------------------
李 11100110 10011101 10001110 | E69D8E
--------------------------------------------------------------------------------------------
例子2:
手动将Unicode编码转换为UFT-8编码。以"严"字为例。
------------------------------------------------------------------------------------------------------------------
Unicode编码(十六进制) | UTF-8编码(二进制) | [码位]位数
------------------------------------------------------------------------------------------------------------------
00000000-0000007F | 0xxxxxxx | 7
00000080-000007FF | 110xxxxx 10xxxxxx | 11
00000800-0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 16
00010000-0010FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21
------------------------------------------------------------------------------------------------------------------
步骤: -->(1) 先获取Unicode字符的十六进制("严"的Unicode码是4E25)
-->(2) 根据十六进制的值判断所处的范围(4E25处在0000 0800-0000 FFFF范围内,对应右边UTF-8编码的范围则 是 1110xxxx 10xxxxxx 10xxxxxx)
-->(3) 获取Unicode字符的二进制(4E25的二进制是:100111000100101) --> 把该二进制的值从右到左依次填入 1110xxxx 10xxxxxx 10xxxxxx 的x中,不足的位补0
-->(4) 结果:
"严"的Unicode二进制: 100 111000 100101
"严"在UFT-8的范围: 1110xxxx 10xxxxxx 10xxxxxx
补齐结果: 11100100 10111000 10100101 转换十六进制-->E4B8A5
可以看到,“严”在Unicode中和UFT-8中的编码(编号)是不一样的。Unicode中是4E25,UFT-8中是E4B8A5。