流畅的python笔记(四)文本和字节序列

本文详细介绍了Python3中字符、字节的概念,包括Unicode编码、字节序列的处理、编解码问题及常见错误。讲解了str与bytes的相互转换,struct模块的应用,以及处理文本文件和字符串规范化的方法。同时,讨论了Unicode数据库和双模式API在正则表达式和os模块中的使用。

目录

一、字符问题  

二、字节概要

bytes与bytearray类型

结构体和内存视图

三、基本的编解码器

四、了解编解码问题

UnicodeEncodeError

UnicodeDecodeError

使用预期之外编码加载模块时抛出SyntaxError

源码中使用非ASCII字符

找出字节序列的编码

BOM:有用的鬼符

五、处理文本文件

Unicode三明治

不能依赖默认编码

六、为了正确比较而规范化Unicode字符串

规范化函数unicodedata.normalize

大小写折叠

极端规范化,去掉变音符号

七、Unicode文本排序

八、Unicode数据库

九、支持字符串和字节序列的双模式API

正则表达式中的字符串和字节序列

os函数中的字符串和字节序列


一、字符问题  

字符串的概念就是一串字符,字符的概念?在英文中,我们可以认为每个数字、字母等都是字符,在中文中,每个汉字也都是字符,还有很多很多的符号也都是字符,但是这是现实世界中的字符,为了将现实世界中的字符存储到计算机上,我们就需要一套编码标准,比如最常见的unicode标准。

        在unicode标准中,主要有两个概念最重要,一个是字符的标识(码位),一个是具体的字节表述(编码得到的二进制流)。

  • 字符的标识即码位,也可以认为是索引,比如我们把现实世界中的所有字符排成一列,然后按按十进制从索引0开始往后标注,则这个索引就是码位。
  • 字符的具体表述取决于所用的编码。编码的作用是把码位转换成字节序列,给计算机存储用的,把字节序列再转换成码位则是解码的过程。
  • 一套字符的码位就是一个字符集,一般所说的编码即是对字符集中的码位进行编码。比如ascii字符集,其编码就是直接把码位转换成对应的8位二进制数。而对于unicode标准中的字符集来说,直接转换成二进制数需要占用太多存储空间,因此另寻了其它的编码方式,比如UTF-8。

        综上,每个字符都对应字符集中的一个码位(可以看成是十进制索引,是字符的编码,可如果把字符类比为学校里的学生,则码位就是学生的学号),每个码位都可以通过特定的编码方式编码成字节序列。从码位(unicode)到字节序列(bytes)是编码,从字节序列到码位是解码。在python3中,str类型即相当于python2中的unicode类型,即内存中以码位对应二进制序列存储,而没有进行编码。

        unicode标准将字符集与编码方式进行了解耦,而ascii和gbk等没有做解耦,因此谈起后者一般指的是字符集和编码都有,且ascii和gbk都是只有一种编码方式。unicode标准的字符集和编码方式都有多种。

        如下例子:

str对象调用encode方法可以转换成bytes对象,bytes对象调用decode方法可以转换成str对象,其中用的转换方法都是utf8,bytes对象字面量都是以b开头的。

二、字节概要

bytes与bytearray类型

python内置了两种基本的二进制序列类型:不可变的bytes类型和可变的bytearray类型。

        bytes或bytearray对象的各个元素是介于0-255之间的整数,但其切片是对应bytes或bytearray类型的二进制序列类型。如下例子:

cafe = bytes("cafe", encoding='utf_8')

print("bytes类型的cafe")
print(cafe)
print(cafe[0])
print(cafe[:1])
print(cafe.decode('utf_8'))

print('\n')

print("bytearray类型的cafe")
cafe_arr = bytearray(cafe)
print(cafe_arr)
print(cafe_arr[-1])
print(cafe_arr[-1:])

        bytes对象是以特定编码的形式存储在内存中,如上例中的cafe,即以utf_8编码的形式构建的bytes对象。其中第一个元素cafe[0]是c,对应码位当然也就是99,因为各个字符集都是兼容ascii的,在ascii中a是97,c自然就是99。但是其只含有一个元素的切片得到的还是一个bytes对象b'c'。把bytes对象解码成unicode对象即可用print直接打印出来。bytearray对象没有字面量的说法,如图所示是以bytes对象字面量加上bytearray()的形式打印的。且其中的元素也是0-255的整数。

        bytes和bytearray序列对象中各个元素都是0到255之间的整数,其实就是代表了一种8位的二进制表示。二进制序列对象中各个字节的值可能用三种不同的方式显示:

比如在例子 b'caf\xc3\xa9' 中,前三个字节的值b'caf'是在可打印的ascii范围内,第四个字节 ‘\xc3’和第五个字节 '\xa9' 则不在,即上边的第三种情况,其它字节的值,使用十六进制转义序列。

        如下边例子,bytes等二进制序列类型相当于对码位进行编码,而unicode或str类型则相当于直接存储码位,下边两行都输出hello,这是因为不管是什么类型的编码,都是兼容ASCII的,而ASCII中编码就等于码位,因此下边两个的输出都是hello,但是一些不在ascii字符集中的字符,其bytes表示和str表示就不一样了。

b = b'hello' 
print(b)
print(b.decode('utf_8'))

        二进制序列类型bytes和bytearray有很多方法都是跟str通用的,也有一个其特有的方法fromhex,作用是解析十六进制数字对,来构建一个二进制序列类型。如下所示,通过一个十六进制序列构建出的二进制序列类型对象b解码成str后是1KΩ。

b = bytes.fromhex('31 4B CE A9')
print(b)
print(b.decode('utf_8'))

 构建bytes或bytearray对象可以调用构造方法,传入如下参数:

  • 一个str对象和一个encoding关键字参数
  • 一个可迭代对象,提供0~255之间的数值
  • 一个实现了缓冲协议的对象(如bytes、bytearray、memoryview、array.array),此时把源对象中的字节序列复制到新键的二进制序列对象中。

        如下例子,使用数组对象来构造bytes对象。定义数组对象的时候必须要指定类型,跟C语言数组比较相似,这里‘h’说明数组元素是16位即2字节的整数,一共有5个元素,因此最后生成的bytes对象octets是一个有10个字节的二进制序列对象。

结构体和内存视图

struct模块提供一些函数,将打包的字节序列转换成不同类型字段组成的元组,或把元组转换成打包的字节序列。struct模块具体分析如下。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值