我们在使用python处理中文字符串时总会遇到一些问题,特别是一些老项目需要用到python2,中文显示乱码,文件读写异常等问题时常发生。
比如:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
通常情况大家都是加上一个decode,encode解决问题,但是并没有完全搞清楚为什么。
本文就把python中的字符串处理一次性讲解清楚~
由于计算机只能处理二进制,字符串类型必须转为数字才能处理,所以字符串是一种特殊的数据类型,它需要编解码才能在计算机中进行处理。
在最早计算机使用ASCII编码,只处理英文字母,数字和一些符号,所以127个字符就够了。
随着计算机发展,全世界各国语言都需要显示,ASCII码不够用了。Unicode编码应用而生,它把所有语言都统一编码。ASCII编码是1个字节,UniCode编码通常是2个字节。
但是英文字符明明1个字节就能搞定的事情,如果都统一使用UniCode,在空间上是一种浪费。所有又出现了UniCode的可变长编码形式UTF-8编码。
UTF-8编码把UniCode字节根据不同的数字编码为1-6个字节,英文字母就是1个字节,中文汉字通常是3个字节。
在Python2中默认的编码是ASCII,不能识别中文字符,需要指定字符编码;
在Python3中默认的编码是Unicode,可以识别中文字符;
在计算节内存中,统一使用Unicode编码。
首先我们要区分下,字符串和字节码。
Python的字符串类型是str,在内存中用Unicode表示,一个字符对应若干个字节。在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes也就是字节码。通常双引号或者单引号表示的,“中文”就是字符串,而b"中文"就是字节码。
Unicode编码字符串由str类型表示;二进制数据字节码由bytes类型表示。
文本编辑从文件读取的UTF-8字符会被转为Unicode字符存在内存里,处理完后,要保存的时候再把Unicode转为UTF-8保存。这里面就有编码和解码的过程。我们先了解什么是编码和解码。
编码(encode):将Unicode字符串转为特定编码格式对应的字节码的过程;就是将字符串转换为字节码
str.encode(encoding="utf-8", errors="strict")
表示将Unicode编码的字符串转为utf-8编码
解码(decode):将特定编码格式的字节码转为对应的Unicode字符串的过程;就是将字节码转换为字符串
bytes.decode(encoding="utf-8", errors="strict")
表示将utf8编码的字节码转为Unicode编码
在使用open读取文件后,read读取了字节码,这时候需要使用文本正确的编码格式进行解码decode为Unicode 。在write写文件时,则需要将Unicode编码encode为你希望的格式。
通常代码中我们通常会在文件开头添加如下代码:
#-*- coding: UTF-8 -*-
意思就是代码使用了UTF-8编码。
python2在读取文件后read(bytes.decode('文件编码格式'))进行一次解码;最后在写入时再write(txt.encode('写入编码格式'))将Unicode进行一次编码。
而在python3后,认为python2的方式太复杂了,每次还要自己转一下。所以将decode和encode作为参数放入了IO接口中,不需要手动指定编码解码了。
下面我们使用代码来理解下上面介绍的内容。
我们在进行字符串操作时,首先要明确下环境的python版本,以及环境默认的编解码格式。
可以使用如下代码确认:
import sys
# 查看python版本
print(sys.version)
# 查看系统的编解码格式
# python2默认ASCII,python3默认UTF8
print(sys.getdefaultencoding())
在python2下运行
在python3下运行
在python2中ASCII码是不能显示中文的,我们可以设置代码使用utf8编码
reload(sys)
sys.setdefaultencoding('utf-8')
下面我们看下encode和decode用法:
'China'.encode('ascii')
输出:b'China'
'中国'.encode('utf-8')
输出:b'\xe4\xb8\xad\xe5\x9b\xbd'
'中国'.encode('ascii')
输出经典错误:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
以上错误就是因为含有中文的字符串是无法用ASCII编码。
"中国".decode()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'decode'
以上错误是因为字符串没有decode。上文我们解释过,decode是将字节码解码为字符串,字符串是不能再解码的。同理b'\xe4\xb8\xad\xe6\x96\x87'字节码也没有encode方法。
b'\xe4\xb8\xad\xe6\x96\x87'.encode()
AttributeError: 'bytes' object has no attribute 'encode'
正确写法只有str.encode()和bytes.decode()
在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。
>>> str_a = u"中国"
>>> byte_b = str_a.encode("utf_8")
>>> str_u = byte_b.decode("utf_8")
>>> str_a == str_u
True
字符数和字节数:
>>> len("China")
5
>>> len("中文")
2
>>> len("China".encode("utf-8"))
5
>>> len("China".encode("ascii"))
5
>>> len("中文".encode("utf-8"))
6
1个英文字母和1个中文都是1个字符
但是1个英文字母只占1个字节,1个中文占3个字节~统计时不要混淆~
参考:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017075323632896
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。