给妹子讲python-S01E08理清python字符编码的使用方法

欢迎关注公众号:python数据科学家php

【要点抢先看】python

1.python中编、解码的本质是文本字符串和字节字符串的相互转换
2.python中编、解码方法举例及过程解析
3.unicode、latin-一、ASCII编码方式的兼容性问题
4.读取二进制文件bash

上一集讲清楚字符编码的基础概念后,我相信这一集再来介绍python中的字符编码就会容易的多。网络

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

首先来介绍一下Python中的两种字符串:函数

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

看一个简单的例子:编码

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

b'apple'
<class 'bytes'>
apple
<class 'str'>
复制代码

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

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

97
b'pple'
[97112112108101]
复制代码

【妹子说】那这和编码、解码有何关联呢?code

从本质上来讲,编码和解码就是str和bytes这两种字符串类型之间的互相转换。

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

首先说说编码,即将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编码方式。

接下来咱们来比较一下unicode、latin-一、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'
复制代码

【妹子说】那对应的,再来谈谈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则是用一个字节来一一对应

【妹子说】计算机用二进制来存储信息,而却能在各类应用中显示咱们须要的文字,这应该是字符编、解码的应用吧。

很对,下面咱们来讲说文本文件读取时的编、解码问题

当一个文件以文本模式打开的时候,被读取的二进制存储数据(也就是存储的字节字符串)会自动被解码(依据显式提供的编码名称或平台默认的编码名称),而且将其返回为一个str。写入文件时,会接受一个str,而且将其传输到文件以前自动编码成字节字符串以供磁盘存储。

当一个文件以二进制模式打开时,须要在open方法的模式字符串参数里添加一个b,此时读取的数据不会以任何方式解码,而是直接返回其原始内容,即一个bytes对象;写入文件时,接受一个bytes对象,而且将其传送到文件中且不进行修改。

在读取文本文件的时候,若是open函数没有声明他们如何编码,python3会因其所运行的系统而选取默认的编码方式,默认状况下,python3 指望文件使用 utf-8进行编码。但因为文件并不老是在同一个系统中被保存和打开,所以会带来乱码的风险,因此咱们须要显式的指定编码。

补充的说明一下,能够很简单的进行一个分类:处理图像文件、设备数据流等,可使用bytes和二进制模式文件处理;而若是要处理的内容实质是文本的内容,例如程序输出、HTML、国际化文本或CSV或XML文件,则可能要使用str和文本模式文件

例如,咱们先把AÄBèC用UTF-8编码后存入utf-8data文件,再来读取他,具体看看这里是如何实现的。

s = 'AÄBèC'

with open('utf-8data','w',encoding='utf-8'as f:
   f.write(s)

with open('utf-8data','r',encoding='utf-8'as f:
   u_str = f.read()
print(u_str)


AÄBèC
复制代码

这里用到的文件读写的方法后面的章节会详细介绍,如今知道他是什么就行了。

以二进制的形式读取文件。

还有一种咱们以前介绍过的用法,文本字符串在存储到磁盘的时候会编码成字节字符,所以咱们也能够先以字节字符串的形式从文件中将其读取,而后再进行解码。

这样作的缘由有二,一种是所接收的多是非文本数据,如一个图像文件;另外一个潜在缘由是没法肯定所读取文本文件的编码,可能须要依据其余信息再肯定:

with open('utf-8data''rb'as f:
   byte_str = f.read()

print(byte_str)
print(byte_str.decode(encoding='utf-8'))

b'A\xc3\x84B\xc3\xa8C'
AÄBèC
复制代码

字符串编、解码在python中很重要,特别是在网络爬虫等网络应用程序中,在后面的实际应用中会感觉到他的做用会愈来愈明显。

【妹子说】这一集的内容不少,细致剖析了python中的两种字符串类型和编、解码的处理方法。再结合以前的三集,就能从基本使用、字符编、解码的维度闭环出一个完整的知识网络了,收获很大。

公众号二维码:python数据科学家:

相关文章
相关标签/搜索