Python中的编码问题(encoding与decode、str与bytes)
Python中的编码问题(encoding与decode、str与bytes)
阅读⽬录
1 引⾔
2 编码发展史
3 str与bytes
4 ⽂件编码
5 ⽹页编码
回到顶部
1 引⾔
在⽂件读写及字符操作时,我们经常会出现下⾯这⼏种错误:
TypeError: write() argument must be str, not bytes
AttributeError: ‘URLError’ object has no attribute ‘code’
UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xa0’ inposition 5747: illegal multibyte sequence
这些错误⼀看就是编码问题, 本篇博⽂总结⼀下Python3⽂件读写及字符操作中的编码。
回到顶部
2 编码发展史
(1)ASCII编码
众所周知,计算机只能处理0和1,任何符号都转换为0和1的序列才能处理。计算机中8个位(bit)作为⼀个字节,所以1个字节能产⽣2的8次⽅个0和1的不同组合,也就是说1个字节做多能表⽰256种字符。ASCII编码就是⽤1个字节来存储字符,计算机最初是美国⼈发明的,他们的符号不多,所以还将8个0和1序列中的第⼀位固定为0,ASCII只能表⽰127个字符。
(2)GB2312编码
unicode码和ascii码区别 美国佬的符号不多,所以ASCII编码够⽤,但是其他国家就不⾏了,每个国家符号数量都不⼀样,就各⾃指定了⾃⼰的编码。例如我们中国就制定了GB2312编码。GB2312编码⽤2个字节表⽰⼀个字符。
(3)Unicode编码
每个国家都⽤⾃⼰的编码,编码⼀朵就容易乱套,也没法交流,所以需要⼀种编码把各个国家的编码都囊括进去,这就是Unicode编码的由来。所以,Unicode也被称为万国码。Unicode编码也⽤2个字节存储⼀个字符。
(4)utf-8编码
Unicode编码解决了编码不能通⽤的问题,但是却容易浪费内存,尤其是在存储英⽂的时候,例如⼀个字符“A”,ASCII编码只需要1个字节就够,但是Unicode编码必须要⽤2个字节。为了解决这⼀问题,就有了utf-8编码。 utf-8编码把存储英⽂依旧⽤⼀个字节,汉字就3个字节。特别是⽣僻的编程4-6字节,如果传输⼤量英⽂,utf-8作⽤就很明显了。
utf-8编码进⾏存储时有极⼤地优势,但是当读取到计算机内存时却不⼤合适,因为utf-8编码是变长的,不⽅便寻址和索引,所以在计算机内存中,还是转化为Unicode编码合适些。这就可以解释为什么
每次读取⽂本时,要将编码转化为Unicode编码,⽽将内存中的字符写⼊⽂件存储时,要将编码转化为utf-8了。
回到顶部
3 str与bytes
在Python3中,⽂本总是为Unicode编码,在类型上为str类,也就是说Python编译器只会把Unicode编码下的⼆进制流显⽰为我们可识别的符号。⼆进制流在Python中也有⼀个专门的类⽤于表⽰这种⼆进制序列,那就是bytes(在Python中这个⼆进制序列显⽰为16进制,但本质还是⼆进制)。⼀个str在不同的编码下就可以转化为不同的bytes(⼆进制流),反之,要将bytes转化为可识别的str就必须⽤对应的编码,否则就会报错。
⽤⼈类语⾔类⽐⼀下:我们要表达“吃饭”这件事物(str),翻译为各个国家的⽂字后有各不相同的表⽰,中⽂表⽰为“吃饭”,英⽂表⽰为“eat”,这就是“吃饭”这个str在不同编码写的表⽰。但官⽅只认中⽂(Pythonstr只认Unicode编码),所以就必须把“eat”⽤英语(编码)的表⽰⽅式转化为中⽂的“吃饭”(Unicode编码),官⽅才会显⽰知道是吃饭这件事。
>>>type(s)
<class'str'>
>>> s1 = s.encode(encoding='utf-8')
>>>type(s1)
<class'bytes'>
>>> s1
b'\xe5\x90\x83\xe9\xa5\xad'
>>> s2 = s.encode(encoding='gb2312')
>>>type(s2)
<class'bytes'>
>>> s2
b'\xb3\xd4\xb7\xb9'
>>> s1.decode('utf-8')
'吃饭'
>>> s2.decode('gb2312')
'吃饭'
回到顶部
4 ⽂件编码
在python 3 中字符是以Unicode的形式存储的,当然这⾥所说的存储是指存储在计算机内存当中,如果是存储在硬盘⾥,Python 3的字符是以bytes形式存储,也就是说如果要将字符写⼊硬盘,就必须对字符进⾏encode。对上⾯这段话再解释⼀下,如果要将str写⼊⽂件,如果以‘w’模式写⼊,则要求写⼊的内容必须是str类型;如果以‘wb’形式写⼊,则要求写⼊的内容必须是bytes类型。⽂章开头出现的⼏种错误,就是因为写⼊模式与写⼊内容的数据类型不匹配造成的。
s1 ='你好'
#如果是以‘w’的⽅式写⼊,写⼊前⼀定要进⾏encoding,否则会报错
with open('F:\\1.txt','w',encoding='utf-8')as f1:
f1.write(s1)
s2 = s1.encode("utf-8")#转换为bytes的形式
#这时候写⼊⽅式⼀定要是‘wb’,且⼀定不能加encoding参数
with open('F:\\2.txt','wb')as f2:
f2.write(s2)
有的⼈会问,我在系统⾥⾯⽤⽂本编辑器打开以bytes形式写⼊的2.txt⽂件,发现⾥⾯显⽰的是‘你好’,⽽不
是‘b’\xe4\xbd\xa0\xe5\xa5\xbd’’,因为⽂本⽂档打开2.txt时,系统会⽤合适的编码将其显⽰为对应的符号,然后才给你看到。
回到顶部
5 ⽹页编码
⽹页编码和⽂件编码⽅法差不多,如下urlopen下载下来的⽹页read()且⽤decoding(‘utf-8’)解码,那就必须以‘w’的⽅式写⼊⽂件。如果只是read()⽽不⽤encoding(‘utf-8’)进⾏编码,⼀定要以‘wb’⽅式写⼊:
以‘w’⽅式写⼊时:
response= url_open('blog.csdn/gs_zhaoyang/article/details/13768925 ’ ,timeout=5 )#⾃定义的⼀个⽹页下载函数#此处以UTF-8⽅式进⾏解码,解码后的数据以unicode的⽅式存储在html中
html = ad().decode(‘UTF-8’)
print(type(html))#输出结果:<class ‘str’>
#这时写⼊⽅式⼀定要加encoding,以encoding
即UTF-8的⽅式对⼆进制数据进⾏编码才能写⼊
with open(‘F:\’,“w” , encoding=‘UTF-8’) as f:
f.write(html)
复制代码
以‘wb’⽅式写⼊:
复制代码
response= url_open('blog.csdn/gs_zhaoyang/article/details/13768925 ’ ,timeout=5 )
html = ad()#此处不需要进⾏解码,下载下来
print(type(html))#输出结果:<class ‘bytes’>
with open(‘F:\’,“wb” ) as f:
f.write(html)
复制代码
如果要在Python3中,对urlopen下载下来的⽹页进⾏字符操作(例如正则匹配、lxml提取),就必须decode成Unicode。
分类: python
标签: decode
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论