linux python 编码,Python中的编码问题(encoding与decode、str与bytes)

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编码

美国佬的符号不多,所以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就必须用对应的编码,否则就会报错。

用人类语言类比一下:我们要表达“Linux公社 www.linuxidc.com”这件事物(str),公社翻译为各个国家的文字后有各不相同的表示,中文表示为“公社”,英文表示为“commune”,这就是“公社”这个str在不同编码写的表示。但官方只认中文(Pythonstr只认Unicode编码),所以就必须把“commune”用英语(编码)的表示方式转化为中文的“公社”(Unicode编码),官方才会显示知道是公社这件事。

>>> s = 'Linux公社 www.linuxidc.com'

>>> type(s)

>>> s1 = s.encode(encoding='utf-8')

>>> type(s1)

>>> s1

b'Linux\xe5\x85\xac\xe7\xa4\xbe www.linuxidc.com'

>>> s2 = s.encode(encoding='gb2312')

>>> type(s2)

>>> s2

b'Linux\xb9\xab\xc9\xe7 www.linuxidc.com'

>>> s1.decode('utf-8')

'Linux公社 www.linuxidc.com'

>>> s2.decode('gb2312')

'Linux公社 www.linuxidc.com'

>>>

8e67a6f253c9864786e18d9b562ba72a.png

a32be767379edfb77f43c11254f72217.png

4 文件编码

在python 3 中字符是以Unicode的形式存储的,当然这里所说的存储是指存储在计算机内存当中,如果是存储在硬盘里,Python 3的字符是以bytes形式存储,也就是说如果要将字符写入硬盘,就必须对字符进行encode。对上面这段话再解释一下,如果要将str写入文件,如果以‘w’模式写入,则要求写入的内容必须是str类型;如果以‘wb’形式写入,则要求写入的内容必须是bytes类型。文章开头出现的集中错误,就是因为写入模式与写入内容的数据类型不匹配造成的。

s1 = '你好,Linux公社www.linuxidc.com'

#如果是以‘w’的方式写入,写入前一定要进行encoding,否则会报错

with open('linuxidc.txt','w',encoding='utf-8') as f1:

f1.write(s1)

s2= s1.encode("utf-8")#转换为bytes的形式#这时候写入方式一定要是‘wb’,且一定不能加encoding参数

with open('linuxidc.com.txt','wb') as f2:

f2.write(s2)

1964cd2f2a32c3853f30de6d9ae39a36.png

7b15a9bca2b7938c2663ad8dd27f867a.png

有的人会问,我在系统里面用文本编辑器打开以bytes形式写入的2.txt文件,发现里面显示的是‘你好,Linux公社www.linuxidc.com’,而不是b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8cLinux\xe5\x85\xac\xe7\xa4\xbewww.linuxidc.com',因为文本文档打开linuxidc.com.txt时,系统会用合适的编码将其显示为对应的符号,然后才给你看到。

5 网页编码

网页编码和文件编码方法差不多,如下urlopen下载下来的网页read()且用decoding(‘utf-8’)解码,那就必须以‘w’的方式写入文件。如果只是read()而不用encoding(‘utf-8’)进行编码,一定要以‘wb’方式写入:

以‘w’方式写入时:

response= url_open('https://www.linuxidc.com/Linux/2018-12/155956.htm' ,timeout=5 )#自定义的一个网页下载函数#此处以UTF-8方式进行解码,解码后的数据以unicode的方式存储在html中

html = response.read().decode('UTF-8')print(type(html))#输出结果:<>#这时写入方式一定要加encoding,以encoding#即UTF-8的方式对二进制数据进行编码才能写入

with open('linuxidc.html.txt',"w" , encoding='UTF-8') as f:

f.write(html)

以‘wb’方式写入:

response= url_open('https://www.linuxidc.com/Linux/2018-12/155956.htm' ,timeout=5)

html= response.read()#此处不需要进行解码,下载下来

print(type(html))#输出结果:<>

with open('linuxidc.html.txt',"wb") as f:

f.write(html)

如果要在Python3中,对urlopen下载下来的网页进行字符操作(例如正则匹配、lxml提取),就必须decode成Unicode。

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python,字符串是以Unicode编码方式存储的,可以表示任意字符,包括文字符。Unicode是一个国际标准,为每个字符分配一个唯一的数字码点,支持世界上所有的字符集,包括文、日文、韩文等。为了在Python正确处理编码,可以使用字符串的encode()和decode()方法。str.encode(encoding="utf-8")可以将字符串按照指定的编码方式编码成二进制数据,而bytes.decode(encoding="utf-8")则可以将二进制数据按照指定的编码方式解码成字符串。此外,Python还提供了一些与字符编码相关的函数和模块,例如chardet模块可以自动检测文本文件的编码方式,而codecs模块提供了一些通用的编码和解码方法。当读写编码的文本文件时,在打开文件时需要指定正确的编码方式,以防止读取文件内容出现乱码。通过在打开文件时使用encoding参数,可以指定文件的编码方式。例如,在使用with语句读取UTF-8编码的文本文件时,可以使用以下代码:with open("test.txt", encoding="utf-8") as f: text = f.read() print(text) [1][2][3123 #### 引用[.reference_title] - *1* *2* *3* [python入门必备:深入了解Python 编码](https://blog.csdn.net/weixin_43170061/article/details/130254082)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值