深⼊理解-字符编码ASCII,GB2312,GBK,Unicode,UTF-8
字符编码
简介
1. 起初再考虑写不写这篇⽂章,感觉这篇⽂章⽐较枯燥乏味,⽽且⾃⼰感觉也没理解的太透彻,就把理解的记录下来,所以这是纪念版
2. 前⽅⾼能,⾮战⽃⼈员请迅速撤离,我要开始了。
Go hard or go home 要么全⼒以赴,要么⾛⼈
No person has the right to rain on your dreams,you do it yourself.
没有⼈有权利给你的梦想泼冷⽔,只有你⾃⼰给⾃⼰的梦想泼冷⽔
看到这样的⽂字是不是很励志?那换⼀种⽅式你还会这样想吗? 16进制版:
476f2068617264206f7220676f20686f6d652089814e485168529b4ee58d742c89814e488d704eba20a4e 6f20706572736f6e20206861732074686520726967687420746f207261696e206f6e20796f7572206472 65616d732c796f7520646f20697420796f757273656c662e206ca167094eba6709674352297ed94f60768 468a660f36cfc51b76c342c53ea67094f6081ea5df17ed981ea5df1768468a660f36cfc51b76c34
然⽽他的字符编码是GB2312的,叫我转化成易懂的字符串,当时我就懵b了。因为当时我对字符编码⼀窍不通,然后就⽹上,查啊查,最后终于想到了解决⽅案
⼏个值的深思的问题
1. 什么是字符?
字符是各种⽂字和符号的总称,包括各个国家⽂字、标点符号、图形符号、数字等。
2. 什么是字符集?
字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等
3. 什么是字符编码?
1、 计算机要准确的处理各种字符集⽂字,需要进⾏字符编码,以便计算机能够识别和存储各种⽂字。
2、 字符编码(encoding)和字符集不同。字符集只是字符的集合,不⼀定适合作⽹络传送、处理,有时须经编码(encode)后才
能应⽤。如Unicode可依不同需要以UTF-8、UTF-16、UTF-32等⽅式编码。
3、字符编码就是以⼆进制的数字来对应字符集的字符。 因此,对字符进⾏编码,是信息交流的技术基础。
4. 概括
1、使⽤哪些字符。也就是说哪些汉字,字母和符号会被收⼊标准中。所包含“字符”的集合就叫做“字符集”。
2、规定每个“字符”分别⽤⼀个字节还是多个字节存储,⽤哪些字节来存储,这个规定就叫做“编码”。
3、各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”⼀般都是同时制定的。因此,平常我们所说的“字符
集”,⽐如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。
4、注意:Unicode字符集有多种编码⽅式,如UTF-8、UTF-16等;ASCII只有⼀种;⼤多数MBCS(包括GB2312,GBK)
也只有⼀种。
5. 有趣的例⼦
1、在显⽰器上看见的⽂字、图⽚等信息在电脑⾥⾯,其实并不是我们看见的样⼦,即使你知道所有信息都存储在硬盘⾥,把它
拆开也看不见⾥⾯有任何东西,只有些盘⽚。假设,你⽤显微镜把盘⽚放⼤,会看见盘⽚表⾯凹凸不平,凸起的地⽅被磁化,凹的地⽅是没有被磁化;凸起的地⽅代表数字1,凹的地⽅代表数字0。硬盘只能⽤0和1来表⽰所有⽂字、图⽚等信息。
2、那么字母”A”在硬盘上是如何存储的呢?可能⼩张计算机存储字母”A”是1100001,⽽⼩王存储字母”A”是
11000010,这样双⽅交换信息时就会误解。⽐如⼩张把1100001发送给⼩王,⼩王并不认为1100001
是字母”A”,可能认为这是字母”X”,于是⼩王在⽤记事本访问存储在硬盘上的1100001时,在屏幕上显⽰的就是字母”X”。也就是说,⼩张和⼩王使⽤了不同的编码表。⼩张⽤的编码表是ASCII,ASCII编码表把26个字母都⼀⼀的对应到2进制1和0上;⼩王⽤的编码表可能是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不同。⼀般地说,开放的操作系统(LINUX 、WINDOWS等)采⽤ASCII 编码,⽽⼤型主机系统(MVS 、OS/390等)采⽤EBCDIC 编码。在发送数据给对⽅前,需要事先告知对⽅⾃⼰所使⽤的编码,或者通过转码,使不同编码⽅案的两个系统可沟通⾃如。
6. 这个例⼦说明了三点
1、不管是任何⽂字图⽚等,最后都会以⼆进制的形式储存到电脑的磁盘中(⽐如记事本A.txt,内容为”ABC”⽂件,在此磁盘
中表现的就是01 01这种⼆进制形式)
盘⽚表⾯凹凸不平,凸起的地⽅被磁化,凹的地⽅是没有被磁化,凸起的地⽅代表数字1,凹的地⽅代表数字0。硬盘只能⽤0和1来表⽰所有⽂字、图⽚等信息。是的 很强势
2、 任何⽂件要储存到电脑中,都会事先进⾏编码,然后储存到电脑的磁盘中,⽐如A.txt⽂件,默认编码为ANSI编码,也可以
编码为UTF-8,然⽽不同的编码⽅式 对应着计算机⽤⼀个字节还是多个字节存储,⽤哪些字节来存储。
3、在双⽅数据进⾏通讯时,要么就保证发送⽅和接受⽅的数据编码是相同,要么就是其中⼀⽅需要转码
7. 什么是字节和位?
字节byte和位bit是电脑⾥的数据量单位。
1.按计算机中的规定,⼀个英⽂的字符占⽤⼀个字节,⽽⼀个汉字以及汉字的标点符号、字符都占⽤两个字节。
2.1个字节等于8位 1byte=8bit
3.1bit在磁盘中以⼆进制01的形式保存 凸起的地⽅代表数字1,凹的地⽅代表数字0
字符编码种类
ASCII
ASCII码是西欧编码的⽅式,采取7位编码,所以是2^7=128,共可以表⽰128个字符,包括34个字符,(如换⾏LF,回车CR等),其余94位为英⽂字母和标点符号及运算符号等。
重点:
字符集:从符号(NUL=”/0”=“空操作字符”)到“Z”再到“DEL”符号
字符编码范围:⼆进制:00000000——01111111 ⼗进制:0-127
占⽤字节:1字节 8bit 盘⽚储存⽅式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸
注:NUL:‘\0’是⼀个ASCII码为0的字符,从ASCII码表中可以看到ASCII码为0的字符是“空操作字符”,它不引起任何控制动作,也不是⼀个可显⽰的字符。
但我们发现ASCII码是没有中⽂编码的,显然在天朝是不够⽤的,于是GB2312诞⽣了。
GB2321
GB2312 是对 ASCII 的中⽂扩展。兼容ASCII。
编码规定:
编码⼩于127的字符与ASCII编码相同,
特性:两个⼤于127的字符连在⼀起时,就表⽰⼀个汉字,前⾯的⼀个字节(称之为⾼字节)从0xA1⽤到0xF7,后⾯⼀个字节(低字节)从0xA1到0xFE,这样我们就可以组合出⼤约7000多个简体汉字了。
字符集:从符号(NUL=”/0”=“空操作字符”)到“Z”到“齄”(简体中⽂)
字符编码范围:16进制:0x0000-(中间有⼀部分是未使⽤的)-0xF7FE
占⽤字节:英⽂ 1字节 8bit 盘⽚储存⽅式:凹凹凹凹凹凹凹凹——凸凸凸凸凸凸凸凸
中⽂ 2字节 16bit 凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹凹——…
GBK
GBK 兼容ASCLL 兼容 GB2312 是GB2312的扩展
但是中国的汉字太多了,我们很快就就发现有许多⼈的⼈名没有办法在这⾥打出来,不得不继续把 GB2312 没有⽤到的码位出来⽤上。后来还是不够⽤,于是⼲脆不再要求低字节⼀定是127号之后的内码,只要第⼀个字节是⼤于127就固定表⽰这是⼀个汉字的开始,不管后⾯跟的是不是扩展字符集⾥的内容。结果扩展之后的编码⽅案被称为 “GBK” 标准,GBK 包括了 GB2312 的所有内容,同时⼜增加了近20000个新的汉字(包括繁体字)和符号。
Unicode
Unicode是国际组织制定的可以容纳世界上所有⽂字和符号的字符编码⽅案。
⽬前的Unicode字符分为17组编排,0x0000⾄0x10FFFF,每组称为平⾯(Plane),⽽每平⾯拥有65536个码位,共1114112个。然⽽⽬前只⽤了少数平⾯。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码⽅案。
UTF-8
UTF-8以字节为单位对Unicode进⾏编码。从Unicode到UTF-8的编码⽅式如下:
UTF-8的特点是对不同范围的字符使⽤不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最⼤长度是6个字节。从上表可以看出,6字节模板有31个x,即可以容纳31位⼆进制数字。Unicode的最⼤码位0x7FFFFFFF 也只有31位。
例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使⽤⽤3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成⼆进制是:0110 1100 0100 1001, ⽤这个⽐特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
举⼀个例⼦:It’s 知乎⽇报
你看到的unicode字符集是这样的编码表:
I 0049
t 0074
’ 0027
s 0073
0020
知 77e5
乎 4e4e
⽇ 65e5
报 62a5
每⼀个字符对应⼀个⼗六进制数字。
计算机只懂⼆进制,因此,严格按照unicode的⽅式(UCS-2),应该这样存储:
I 00000000 01001001
t 00000000 01110100
’ 00000000 00100111
s 00000000 01110011
00000000 00100000
知 01110111 11100101
乎 01001110 01001110
⽇ 01100101 11100101
报 01100010 10100101
这个字符串总共占⽤了18个字节,但是对⽐中英⽂的⼆进制码,可以发现,英⽂前9位都是0!浪费啊,浪费硬盘,浪费流量。
怎么办?
UTF
UTF-8是这样做的:
1. 单字节的字符,字节的第⼀位设为0,对于英语⽂本,UTF-8码只占⽤⼀个字节,和ASCII码完全相同;
2. n个字节的字符(n>1),第⼀字节的前n位设为1,第n+1位设为0,后⾯字节的前两位都设为10,这n个字节的其余空位填充该字符unicode码,⾼
位⽤0补⾜。
这样就形成了如下的UTF-8标记位:
⾼位字节低位字节低位字节低位字节低位字节低位字节0xxxxxxx
110xxxxx10xxxxxx
1110xxxx10xxxxxx10xxxxxx
11110xxx10xxxxxx10xxxxxx10xxxxxx
111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx … ….
⽐如”知”字 在Unicode中占⽤两个字节,那么第⼀字节(我叫它⾼位字节)的前两位设位1,第三位设为10,后⾯低位字节设为前两位设为10, “知”→ 11100111 10011111 10100101
怎么知道“知”字占⽤两个字节的?⾸先要知道Unicode字符集中,“知”字的编码为77e5,然后转化为⼆进制流01110111 11100101的bit,每8bit等于1byte 所以就占两个字节
于是,”It’s 知乎⽇报“就变成了:
unicode码和ascii码区别I 01001001
t 01110100
’ 00100111
s 01110011
00100000
知 11100111 10011111 10100101
乎 11100100 10111001 10001110
⽇ 11100110 10010111 10100101
报 11100110 10001010 10100101
和上边的⽅案对⽐⼀下,英⽂短了,每个中⽂字符却多⽤了⼀个字节。但是整个字符串只⽤了17个字节,⽐上边的18个短了⼀点点。
剧透:⼀切都是为了节省你的硬盘和流量。
⼀图解忧愁