python中的编码格式有哪些_python中编码格式
背景最近⽤python写⼀个在⼿机上安装、启动、卸载apk的脚本,在⾃⼰测试的时候⽤的是⼀个不带中⽂的apk,没有碰到什么问题,但是当真正去跑脚本的时候,突然报错了,查看错误信息,是 编码格式有问题。
所以就趁机把python的编码格式了解了⼀下。然后这⾥写篇⽂章来记录下解决问题的过程。
这⾥⽤的python版本是2.x,3.x对编码这⼀块有优化。
常见的编码格式
ASCII码计算机内部,所有的信息最终都表⽰为⼀个⼆进制的字符串,每⼀个⼆进制位(bit)有0和1两种状态,因此⼋个⼆进制位(也就是⼀个字节)可以组合出256中状态,上个世纪60年代,美国制定了⼀套字符编码,对英语字符与⼆进制位之间的关系,做了统⼀规定,这种被称为ASCII码,⼀直沿⽤⾄今。
ASCII码⼀共规定了128个字符的编码,⽐如空格“SPACE”是32(⼆进制00100000),这128个字符(包括32个不能打印出来的控制符号)只占⽤了⼀个字节的后⾯7位,最前⾯的1位统⼀是0。
⾮ASCII编码
英语⽤128个字符就够了,但是⽤来表⽰其他语⾔,128个字符就不够了,于是⼀些欧洲国家就决定,利⽤字节中闲置的最⾼位编⼊新的符号,这样⼀来,这些欧洲国家使⽤的编码体系,可以表⽰最多256个符号。
但是,⼜出现新的问题,不同国家有不同的字母,因此,哪怕他们都使⽤256个符号的编码⽅式,代表的字母却不⼀样,⽐如同样的都是130,但是法语、希伯来语、俄语代表的字母是不⼀样的,但是不管怎么样,所有这些编码⽅式中,0–127表⽰的字符是⼀样的,不⼀样的只是128–255的这⼀段。
⾄于亚洲国家的⽂字,使⽤的符号就更多了,汉字就多达10万左右,⼀个字节只能表⽰256种符号,肯定是不够的,就必须使⽤多个⾃⼰表达⼀个字符,⽐如,简体中⽂常见的编码⽅式是GB2312,使⽤两个字节表⽰⼀个汉字,所以理论上最多可以表⽰256*256=65536个符号。
这⾥需要指出,虽然都是⽤多个字节表⽰⼀个符号,但是GB类的汉字编码与后⽂的Unicode和UTF-8是毫⽆关系的。
UnicodeUnicode是⼀个很⼤的集合,是⼀种所有符号的编码,现在的规模可以容纳100多万个符号,每个符号的编码都不⼀样。
需要注意的是,Unicode只是⼀个符号集,它只规定了符号的⼆进制代码,却没有规定这个⼆进制代码
如何存储,⽐如,汉字的‘严’的unicode是⼗六进制数4E25,转换成⼆进制数⾜⾜有15位(100111000100101),也就是说这个符号表⽰⾄少需要两个字节。表⽰其他更⼤的符号,可能需要3个字节或者4个字节,甚⾄更多。
这就有两个严重的问题,第⼀个问题是:如何才能区别Unicode和ASCII?计算机怎么知道三个字节表⽰⼀个符号,⽽不是分别表⽰三个符号呢?第⼆个问题是:如果英⽂字母⽤⼀个字节表⽰就够了,如果Unicode统⼀规定,每隔符号⽤三个或4个字节表⽰,那么每个英⽂字母前都必然有⼆到三个字节是0,这样对于存储是极⼤的浪费。
然后出现的结果是:1)出现了Unicode的多种存储⽅式,也就是说许多种不同的⼆进制格式,可以⽤来表⽰Unicode。 2)Unicode在很长⼀段时间⽆法推⼴,直到互联⽹的出现。
UTF-8互联⽹的普及,强烈要求出现⼀种统⼀的编码格式。UTF-8就是在互联⽹上使⽤最⼴的⼀种Unicode的实现⽅式,其他的实现⽅式还包括UTF-16(字符⽤两个字节或4个字节表⽰)和UTF-32(字符⽤四个字节表⽰),需要注意的是这⾥的关系是,UTF-8是Unicode的实现⽅式之⼀。
UTF-8最⼤的特点是:它是⼀种变长的编码⽅式,它可以使⽤1~4个字节表⽰⼀个符号,根据不同的符号⽽变化字节长度。它的编码规则很简单,有两条:
对于单字节的符号,字节的第⼀位设为0,后⾯7位这个符号的Unicode码,因此对于英⽂字母,UTF-8编码和ASCII码是相同的。
对于n字节的符号(n>1),第⼀个字节的前n位都设为1,第n+1位设为0,后⾯字节的前两位⼀律设为10,剩下的没有提及的⼆进制位,全部为这个符号的Unicode码。
下图总结了编码规则,字母x表⽰可⽤编码的位。
跟据上表,解读UTF-8编码⾮常简单。如果⼀个字节的第⼀位是0,则这个字节单独就是⼀个字符;如果第⼀位是1,则连续有多少个1,就表⽰当前字符占⽤多少个字节。
举个例⼦,”严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三⾏的范围内(0000 0800-0000 FFFF),因此”严”的UTF-8编码需要三个字节,即格式是”1110xxxx 10xxxxxx 10xxxxxx”。然后,从”严”的最后⼀个⼆进制位开始,依次从后向前填⼊格式中的x,多出的位补0。这样就得到了,”严”的UTF-8编码是”11100100 10111000 10100101”,转换成⼗六进制就是E4B8A5。可以结合着上图更好理解。
Little endian和Big endian上⾯提到,Unicode码可以采⽤UCS-2格式直接存储,以汉字“严”为例,Unicode码是4E25,需要⽤两个字节存储,⼀个字节是4E,另⼀个字节是25,存储的时候4E在前,25在后,就是Big Endian⽅式,25在前,4E在后就是Little endian⽅式。
那么计算机是怎么知道某⼀个⽂件到底采⽤哪⼀种⽅式编码? Unicode规范中定义,每⼀个⽂件的最前⾯分别加⼊⼀个标识编码顺序的字符,这个字符的名字叫做“零坎都⾮换⾏空格”⽤FEFF表⽰,这正好是两个字节,FF⽐FE⼤1,如果⼀个⽂本⽂件的头两个字节是FEFF,就表⽰该⽂件采⽤⼤头⽅式,如果头两个字节是FFFE,就表⽰该⽂件采⽤⼩头⽅式。
GBK && GB2312GB2312是国家制定的汉字编码标准,使⽤双字节编码,共收⼊6763个汉字和682个⾮汉字图形字符,GBK即对国际编码的扩展,在GB2312的基础上进⾏扩展形成的,使⽤双字节编码⽅式,共收⼊21003个汉字,从⽽满⾜了汉字使⽤的需要。
开始
简介字符串是python中最常见的数据类型,很多时候会⽤到⼀些不属于标准ASCLL字符集的字符,这时候代码很可能会抛出UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xc4 in position 10: ordinal not in range(128)异常,这是⼀个让初学者头疼的问题。
字符串在python内部的标识是Unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,也就是说先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另⼀种编码。但是,python2.x的默认编码格式是ASCLL,因此在没有指定python源码编码格式的情况下,源码中所有字符都会被默认为ASCLL码,也因为这个根本原因,在python2.x中经常会遇到UnicodeDecode
Error或者UnicodeEncodeError。
关于UnicodeUnicode是⼀种字符集,它为每⼀种现代或古代使⽤的⽂字系统出现的每⼀个字符都提供了统⼀的序列号,规定了符号的⼆进制代码,但没有规定这个⼆进制代码如何存储,也就是说:Unicode的编码⽅式是固定的,但是实现⽅式根据不同的需要有很多种,常见的有UTF-8、UTF-16、UTF-32等。
为了能够处理Unicode数据,同时兼容python某些内部模块,python 2.x中提供了Unicode这种数据类型,通过decode和encode⽅法可以将其他编码和Unicode编码相互转化,但同时也引⼊了UnicodeDecodeError和UnicodeEncodeError异常。
常见的⼏种编码异常
SyntaxError: Non-ASCII character这种异常最不容易出现,也最容易处理,主要原因是Python源码⽂件中有⾮ASCII字符,⽽且同时没有声明源码编码格式,例如:
1
2s = '中⽂'
print s # 抛出异常
UnicodeDecodeError这个异常有时候会在调⽤decode⽅法时出现,原因是Python打算将其他编码的字符转化为Unicode编码,但是字符本⾝的编码格式和decode⽅法传⼊的编码格式不⼀致,例如:
1
2
3
4
5#!/usr/bin/python
# -*- coding: utf-8 -*-
s = '中⽂'
s.decode('gb2312') # UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 2-3: illegal multibyte sequence
print s
上⾯这段代码中字符串s的编码格式是utf-8,但是在使⽤decode⽅法转化为Unicode编码时传⼊的参数是‘gb2312’,因此在转化的时候抛出UnicodeDecodeError异常。还有⼀种情况是在encode的时候:
1
2
3
4
5#!/usr/bin/python
# -*- coding: utf-8 -*-
s = '中⽂'
print s
UnicodeEncodeError错误的使⽤decode和encode⽅法会出现这种异常,⽐如:使⽤decode⽅法将Unicode字符串转化的时候:
1
2
3
4
5#!/usr/bin/python
# -*- coding: utf-8 -*-
s = u'中⽂'
unicode汉字s.decode('utf-8') # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
print s
上⾯这个错误可以这么理解:s是⼀个Unicode的字符串,然后想decode成utf-8格式的,这显然不合理。
解决⽅法
遵循PEP0263原则,声明编码格式在PEP 0263 – Defining Python Source Code Encodings中提出了对Python编码问题的最基本的解决⽅法:在Python源码⽂件中声明编码格式,最常见的声明⽅式如下:
1
2#!/usr/bin/python
# -*- coding: -*-
使⽤ u’中⽂’ 替代 ‘中⽂’1
2str1 = '中⽂编码'
str2 = u'中⽂编码'
Python中有以上两种声明字符串变量的⽅式,它们的主要区别是编码格式的不同,其中,str1的编码格式和Python⽂件声明的编码格式⼀致,⽽str2的编码格式则是Unicode。
如果你要声明的字符串变量中存在⾮ASCII的字符,那么最好使⽤str2的声明格式,这样你就可以不需要执⾏decode,直接对字符串进⾏操作,可以避免⼀些出现异常的情况。
Reset默认编码Python中出现这么多编码问题的根本原因是Python 2.x的默认编码格式是ASCII,所以你也可以通过以下的⽅式修改默认的编码格式:
1
2import sys
sys.setdefaultencoding('utf-8')
这种⽅法是可以解决部分编码问题,但是同时也会引⼊很多其他问题,得不偿失,不建议使⽤这种⽅式。
终极原则:decode early, unicode everywhere, encode late最后分享⼀个终极原则:decode early, unicode everywhere, encode late,即:在输⼊或者声明字符串的时候,尽早地使⽤decode⽅法将字符串转化成unicode编码格式;
然后在程序内使⽤字符串的时候统⼀使⽤unicode格式进⾏处理,⽐如字符串拼接、字符串替换、获取字符串的长度等操作;
最后,在输出字符串的时候(控制台/⽹页/⽂件),通过encode⽅法将字符串转化为你所想要的编码格式,⽐如utf-8等。
Python 3.x中的Unicode在Python 3.0之后的版本中,所有的字符串都是使⽤Unicode编码的字符串序列,同时还有以下⼏个改进:
默认编码格式改为unicode
所有的Python内置模块都⽀持unicode
不再⽀持u’中⽂’的语法格式
所以,对于Python 3.x来说,编码问题已经不再是个⼤的问题,基本上很少遇到上述的⼏个异常。
+++++++++

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。