简介
以前一直对字符编码很模糊,感觉编码方式有很多,在网上查资料也总是看的晕头转向,所以在这里先将几种常见的编码方式的关系总结一下。
常见的字符编码——ASCII
、Unicode
、GBK
、UTF-8
-
ASCII
ASCII编码的全称是American Standard Code for Information Interchange
,美国信息互换标准代码。这是一种最早的、只用来保存英文文字的编码方式。ASCII编码方式只使用了1个字节(8比特位,可以组合出256种不同的状态)中0~127种组合存储了英文的文字。
-
GBK
当计算机普及到国内时,因为汉字的常用字就有将近6000个,使用ASCII编码已经完全不能满足使用的需求了。
所以在1981年,国家标准总局发布了GB2312
(中国国家标准简体中文字符集),使用2个字节的组合,当两个大于127的字符连在一起时,就表示一个汉字,这样就组合出了7000多个简体字。
后来因为汉字的扩展需求,发布了GBK
标准,K
是扩展一次汉语拼音的声母。即不再要求第二个字节大于127,只要第一个字节大于127,则表示这是一个汉字的开始。这样共收录了将近22000个汉字和符号。且兼容了GB2312标准。
2005年时修订了GB18030
标准,支持了国内少数民族的文字,共收录汉字70000余个。兼容了GBK
标准。
-
Unicode
就如国内定义了GB2312标准一样,当时各个国家都规定了适用于自己语言的一套编码方式。但是这就导致各国相互之间谁也不懂谁的编码,装错字符系统就会导致显示全是乱码。
所以这时ISO(International Standards Organization
,国际标准化组织)推出了Unicode标准
用以解决这个问题。
Unicode标识以2个字节长度的数字来标识所有字符,除了英文以外的字符全部重新进行了统一编码。
注意Unicode只是一种标准,不是编码方式,给予了每个字符一个16比特位的数字标识,至于这个字符在内存中是由几个字节存储,并不是Unicode标准规定的。
-
UTF-8
Unicode标准制定后,在很长的一段时间内无法推广,直到互联网的普及,强烈要求出现一种统一的编码方式。然后就诞生了UTF-8,这个使用Unicode标准的编码方式。
注意:因此,UTF-8是Unicode标准的一种实现方式。
UTF-8的编码规则很简单,只有两条:
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和ASCII码是相同的。
- 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表为编码规则,字母x
表示可用编码的位。
Unicode符号范围 | UTF-8编码方式(二进制) |
---|---|
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
以汉字严
为例,演示如何实现UTF-8编码:
严
的Unicode码是4E25
(100111000100101
),根据上表,可以发现4E25
处在第三行的范围内(0000 0800 - 0000 FFFF
),因此严
的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx
。然后,从严
的最后一个二进制位开始,依次从后向前填入格式中的x
,多出的位补0
。这样就得到了,严
的 UTF-8 编码是11100100 10111000 10100101
,转换成十六进制就是E4B8A5
。
由此可见,汉字的Unicode码和UTF-8编码是不同的,它们之间可以通过规则进行转换。
注意 : 汉字的Unicode码是2个字节,而UTF-8码是3个字节
Python 中的编码方式转换
Python3中的字符序列类型有两种:str
和bytes
。
bytes对象是一串十六进制格式字符序列,如b'\xe6\x88\x91'
,前方的b
标示这串字符是bytes对象。
将bytes对象通过上述的某种编码方式可以解析为字符串,如将b'\xe6\x88\x91'
使用UTF-8编码方式解码得到汉字我
,而使用GBK编码方式解码无法得到完整的汉字。
Python3中使用encode()
和decode()
进行字符与二进制序列之间的转换,可以这样理解:
encode
(编码)就是把人能看懂的汉字,转换为机器能看懂的二进制序列。
decode
(解码)就是把人看不懂的二进制序列,转换为汉字。
使用encode()
和decode()
时,有个encoding
参数,默认值为UTF-8
,指定了对字符串进行编码或解码时,使用的编码方式。
有关文件的编码方式
前面说了那么多,还没有讲到有关文件的编码方式,而且可能平时使用open()
打开文件read()
的时候,并没有指定编码方式,也能够正常打印出来文件的内容。
文件的编码方式是在open()
是指定的,有个encoding
参数,作用和字符串解码一样,如果以非二进制模式(b
)打开文件,会默认通过UTF-8
方式打开。
所以一份GBK
编码的文件,如果不以二进制模式打开、且不设置这个encoding
参数,是会报解码错误的(UnicodeDecodeError
)。
当然,如果以二进制模式打开文件,再读取到的文本就已经是二进制序列了,不涉及encode
问题,而是该以什么解码方式将二进制序列转换为人可以读懂的汉字。
所以对于一个未知编码方式的文件,如何通过代码获取其编码方式,然后转换为我们所期望的编码方式呢?
Python提供了一个第三方库chardet
,是char detect
的缩写,字符监测。
将二进制序列传入chardet.detect()
方法,然后会返回一个字典。该字典有3个键值。
{
'encoding': 'GB2312',
'confidence': 0.99,
'language': 'Chinese'
}
encoding
是所识别出来该二进制序列的编码方式。
confidence
是所识别出来的encoding
正确概率(1.0表示100%)。
language
是该编码方式适用的语言。
可以根据confidence
概率决定是否使用encoding
编码方式。