分享

不可不知的Python字符编码使用技巧(中)

 tology 2018-07-18

《不可不知的Python字符编码使用技巧(上)》中,我们讲清楚了字符编码的基础概念,我相信由此再来介绍python中的字符编码就会容易的多。

通过上一集我们知道,ASCII码(包括其最常见的超集Latin-1)依赖这样的一个假设,即每一个字符与一个字节相匹配,由于存在太多的字符,因此不可避免的会出现问题,Unicode字符集通过使用4个字节来表示1个字符,则解决了该问题。

1.Python中的两种字符串

Python中有两种字符串:文本字符串和字节字符串。其中文本字符串类型被命名为str,内部采用Unicode字符集(兼容ASCII码),而字节字符串则直接用来表示原始的字节序列(用print函数来打印字节字符串时,若字节在ascii码范围内,则显示为ascii码对应的字符,其余的则直接显示为16进制数),该类型被命名为bytes

看一个简单的例子:
代码片段:

s = 'apple'
b = b'apple'
print(b)
print(type(b))
print(s)
print(type(s))

运行结果:

b'apple'
<class 'bytes'>
apple
<class 'str'>

再近距离的看看bytes类型字节字符串,本质上它就是一串单字节16进制数
代码片段:

b = b'apple'
print(b[0])
print(b[1:])
print(list(b))

运行结果:

97
b'pple'
[97, 112, 112, 108, 101]

2.编码、解码的本质内涵

上一小节介绍的Python的两种字符串,和编码、解码有何关联呢?其实从本质上来说,编码和解码就是str和bytes这两种字符串类型之间的互相转换

str包含一个encode方法,使用特定编码将该字符串转换为一个bytes,这称之为编码bytes类包含了一个decode方法,也接受一个编码作为单个必要参数,并返回一个str,这称之为解码。这种转换操作是显式的操作,且必须根据数据被编码时采用的编码类型进行解码。

3.编码操作

3.1.基本操作方法

首先说说编码,即将unicode的str文本字符串转换为bytes的字节字符串,可以显式的传入指定编码(一般来说采用utf-8编码),或使用平台的默认编码。
代码片段:

s = 'π排球の'
b1 = s.encode('utf-8')
b2 = s.encode()
print(b1)
print(b2)

运行结果:

b'\xcf\x80\xe6\x8e\x92\xe7\x90\x83\xe3\x81\xae'
b'\xcf\x80\xe6\x8e\x92\xe7\x90\x83\xe3\x81\xae'

那么我们看看,在不写编码的时候,平台默认的编码方式到底是什么
代码片段:

import sys
print(sys.platform)
print(sys.getdefaultencoding())

运行结果:

win32
utf-8

可以看出我这个平台默认选择的是utf-8编码方式。

3.2.编码的兼容性问题

接下来我们来比较一下unicode、latin-1、ASCII编码方式的兼容性问题:

首先,非ASCII字符无法使用ASCII编码转换成字节字符串
代码片段:

s = 'π排球の'
b = s.encode('ascii')

运行结果:

Traceback (most recent call last):
 File 'E:/12homework/12homework.py', line 2in <module>
   b = s.encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3:
 ordinal not in range(128)

其次,Latin-1和unicode编码方式不兼容

例如,重音字符会在latin-1字符集和unicode字符集中同时存在,但是通过latin-1和unicode编码方式编出来的字节流是不一样的,注意,虽然unicode字符集是包含了latin-1字符集,但是不代表utf-8编码方式兼容latin-1编码方式。因为unicode字符集中除了ascii字符集外,都是采用多字节的编码方式,而latin-1一律采用单字节的方式
代码片段:

s = 'Äè'
print(s.encode('utf-8'))
print(s.encode('latin-1'))

运行结果:

b'\xc3\x84\xc3\xa8'
b'\xc4\xe8'

只有ascii字符集中的字符,三种编码方式得到的结果才完全一致。对unicode进行编码的时候,针对常规的7位ASCII文本,由于utf-8以及latin-1编码方式都是兼容ASCII的,所以结果都是一样的。
代码片段:

s = 'abc'
print(s.encode('utf-8'))
print(s.encode('latin-1'))
print(s.encode('ascii'))

运行结果:

b'abc'
b'abc'
b'abc'

4.解码操作

那对应的,再来谈谈decode解码方法吧。

将bytes类型字符串转换成str类型的unicode文本字符串也是一样,要么指定编码参数,要么使用平台的默认参数。这个例子中,我们要操作的字节字符串b是通过utf-8编码方式对文本字符串'π排球の'编码而形成的。
代码片段:

b = b'\xe6\x8e\x92\xe7\x90\x83'
s1 = b.decode(encoding='utf-8')
s2 = b.decode()
s3 = b.decode(encoding='latin-1')

print(s1)
print(s2)
print(s3)

运行结果:

排球
排球
排球

值得注意的是,最后一行代码想通过latin-1解码字节字符串,由于字节字符串是通过utf-8编码形成,因此这样解码形成得到的只能是乱码。

因为,utf-8编码是用两个字节来表示非ASCII的高128字符,而latin-1则是用一个字节来一一对应


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多