在理解字符编码之前,先做好准备工作:
- 工具:UltraEdit,windows自带文本编辑器。
- 约定:GBK代表GB2312,GBK,GB18030
首先在UltraEdit输入一串文字分别保存为不同编码格式查看其16进制。
图1
编码格式 |
GBK |
ANSI |
UNICODE |
16进制值 |
31 32 41 61 C1B7 CFB0 |
31 32 41 61 C1B7 CFB0 |
31 32 41 61 7EC3 4E60 |
编码格式 |
UTF-8 |
UTF-16LE |
UTF-16BE |
16进制值 |
31 32 41 61 E7BB83 E4B9A0 |
3100 3200 4100 6100 C37E 604E |
0031 0032 0041 0061 7EC3 4E60 |
注:输入内容中的6个字符和图1中每种编码下空格隔开的16进制一一对应。
从上图得出如下现象(后面会对这些现象解释原由):
- 对于输入内容的数字和英文部分在GBK,ANSI,UNICODE,UTF-8中16进制一致,在UTF-16BE/LE所占用的字节数不一致。
- GBK,ANSI的16进制一致。
- 对于输入内容,把UTF-16BE每个字符的高字节和低字节对调就等于UTF-16LE。
ASCII:
在解释图1现象之前,了解一下最基本的单字节编码系统ASCII(点击查看详情),然后得出结论:
- ASCII是基本单字节编码系统,二进制格式0xxxxxxx,范围为0-127,16进制范围00-7F
- 只能表示很小范围的字符(控制字符+数字+英文等),不能表示中文(GB系列的诞生)。
- ASCII在GBK,UTF-8,ANSI,UNICODE表现一致,后者对ASCII做了兼容,是其超集(UNICODE有点特殊,后面会讲到)。在UTF-16(LE/BE)上占用字节数不一样(前者一个字节,后者两个字节)。
GB系列:
在解释了ASCII和其他几种编码的异同点以及作用后。我们发现一个问题:除了ASCII表上的字符之外,其他的都表示不了,包括中文!包括中文!包括中文!于是GB系列(包括GB2312,GBK,GB18030)诞生了,旨在解决中文字符相关的问题(简单了解就好)。
GB2312参考:GB2312(点击查看详情),GB2312区位码(点击查看)
通过上述参考内容得出GB2312结论如下:
- GB2312最先诞生,解决简体中文的编码问题,用两个字节表示一个字符(兼容ASCII的部分,ASCII部分仍然一个字节)。
- GB2312采用区位码的方式表示,一共1-87(十进制)个分区,一共1-94(十进制)个码位。也就是说GB2312一共87个分区,每个分区有94个码位,一共可以表示:87x94=8178个字符,其中中文字符16-87分区,一共:(87-15)x94=6768个中文字符。
- 为了兼容ASSCII,其高字节必须大于127(0x7F),于是规定:高字节编码=分区编号+0xA0,低字节编码=码位编号+0xA0,于是得知高字节编码范围:(1+0xA0)~(87+0xA0)-->0xA1~0xF7,同理,低字节范围:0xA1-0xFE,合并后:0xA1A1~0xF7FE。、
- 0xA0=160,所以不兼容ASCII扩展(范围128~255),对ASCII扩展感兴趣的朋友可以自行查找资料。
- 同时我们发现GB2312并不完美,很多生僻字和繁体字并没有与之对应的编码(GBK的诞生)。
GBK参考:GBK(点击查看详情),GBK区位码(点击查看)
为了解决上述结论5,诞生了GBK,通过GBK参考得出结论如下:
- GBK是对GB2312的扩充,兼容GB2312,同时兼容BIG5(台湾繁体编码),支持中日韩新等统一编码规范(CJK)
- 同样采用了区位码,分区:0x81~FE,码位:0x40~FE。不用+0xA0,合并后范围:0x8140-FEFE。
- 由于历史原因(windows,linux上中文默认编码都是GBK),导致GBK是GB系列windows,linux的主流。
- GB2312和GBK都不支持少数民族文字,同时都不支持国际化,于是诞生GB18030。
GB18030参考:GB18030(点击查看详情),GB18030编码研究(点击查看)
为了解决上述结论4,诞生了GB18030,通过GB18030参考得出结论如下:
- GB18030是对GBK的扩充,目前主流,新增了少数名族文字,支持单字节,双字节,四字节。
- 实现了UCS4(后面会详细讲到),国际统一标准。
以上就了解完了GB系列的相关知识,细心的朋友会发现两个问题:
- 假设有很多种类似GBK的编码,那么我们到底该选择那种编码呢?(ANSI的诞生)
- GB18030是如何保证兼容GBK的情况下同时实现UCS4的呢?(暂时保留)
ANSI:
为了解决上述问题1,我们为每个国家设置不同的默认编码,那么这个被设置的编码同时又叫做ANSI(微软干的好事),说以在中国ANSI=GBK。好处是解决了字符编码选择问题。但是不能解决本质问题:
不同编码相互转换问题。如GB2312和BIG5之间大部分字符是不能相互转换的(上面的知识点可以证明)。我们可以试想几种方式来解决。
- 通过翻译的方式来映射(难度太大,现实)。
- 字符统一编码,所有的字符编码不重复,并被所有人认可。(UNICODE的诞生)。
UNICODE:
UNICODE参考:UNICODE(点击查看详情)
全称:unicode character set 别名UCS(后面提到UCS和UNICODE是一个意义),对照参考可以得出以下结论:
- 包含UCS2和UCS4,分别用最大2个和4个字节来给字符进行逻辑编码。
- UNICODE只是为字符制定了统一的逻辑编码(之后统一简称UNICODE码),并没有定义其在计算机中的存储编码。
- 对于储存编码并不强求兼容已经存在的任何一种编码方式,但是UNICODE码却是和ASSCII编码的数值大小保持了一致。
- UNICODE只是制定了一套编码规范,并没有具体的实现(结论3的延续),需要开发商自行实现(UTF16的诞生)。
UTF-16:
UTF全称:Unicode Transformation Format
这里讲解的UTF-16,主要是UTF-16BE(大端),UTF-16LE(小端)自行理解。一般我们会在文本首部加上FEFF来表示大端,FFFE来表示小端。这种方式通常称为BOM(Byte Order Mark)。对UTF-16加上BOM可以保证字符编码的正确解析,UTF-16中的16表示16位,即2个字节定长(65536个字符),实现了UCS2。
其实UTF-16的实现方式很简单,就是把UNICODE码一一对应过来,高位不足就补0,直到补满16位,所以才导致ASCII篇的结论3(但是并不兼容ASCII)。同时我们会发现如下问题:
- 在网络通信中大小端问题需要自己解决,能表示的字符范围有限。(UTF-8的诞生)
UTF-8:
UTF-8,目前应用最广泛,前景最好的编码,没有之一,极力推荐。
特点:变长(位数是8的倍数),灵活,表示范围广,对UCS4的实现。
我们把UNICODE码用二进制表示,其长度记着LEN,UTF-8所占字节数记着N,存储编码规则如下:
- 当LEN<8,N=1,同时与UNICODE码保持一致,(所以兼容ASCII)。
- 当LEN>=8,N=LEN/6+1,依据:最高一个字节的前n个连续的1表示n个字节,后面紧跟一个0。剩下n-1个字节,每个字节的前两位都以10表示。如2字节表示:110xxxxx 10xxxxxx , 3字节1110xxxx 10xxxxxx 10xxxxxx。 最后推理出 N<8。 同时N越大存储浪费也越大。
-
UTF-32:
没啥好说的,类似UTF-16,比UTF-8/16表示范围大。
总结: