第4章 文本和字节序列(上)

4.1 字符问题

Unicode标准把字符的标识和具体的字节表述进行如下区分:

  • 字符的标识,即码位,是0~1114111的数字(十进制),在Unicode标准中以4—6个十六进制数标识,而且前缀加“U+”。如字母A的码位是U+0041。
  • 字符的具体表述取决于所用的编码。编码是在码位和字节序列之间转换时使用的算法。在UTF-8编码中,A(U+0041)的码位编码成单个字节\x41

将码位转换成字节序列的过程是编码,把字节序列转换成码位的过程是解码。如下例:

>>> b="哈哈哈".encode('utf-8')
>>> b
b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88'
>>> b.decode('utf-8')
'哈哈哈'

4.2 字节概要

Python内置两种基本二进制序列类型:Python3引入的不可变bytes类型和Python2.6添加的可变bytearray类型。
二者对象的各个元素是介于0-255之间的整数。二进制序列的切片始终是同一类型的二进制序列,包括长度为1的切片。如下所示:

>>> a=bytes('哈哈哈',encoding='utf-8')
>>> a
b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88'
>>> a[0]
229
>>> a[:1]
b'\xe5'
>>> a_arr=bytearray(a)
>>> a_arr
bytearray(b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88')
>>> a_arr[-1:]
bytearray(b'\x88')

a[0]返回229,a[:1]返回bytes对象切片。
虽然二进制序列其实是整数序列,但是它们的字面量表示法表明其中有ASCII文本。因此,各个字节的值可能会使用如下三种不同的显示方式:

  • 可打印的ASCII范围内的字节(从空格到~),使用ASCII字符本身
  • 制表符、换行符、回车符和\对应的字节,使用转义序列\t、\n、\r和\
  • 其他字节的值,使用十六进制转义序列

结构体和内存视图

struct模块提供了一些函数,可把打包的字节序列转换成不同类型字段组成的元组,还有一些函数用于执行反向转换,把元组转换成打包的字节序列。
struct模块能处理bytes、bytearray和memoryview对象。

4.3 基本的编解码器

在这里插入图片描述
*表明该编码不支持表示该字符
典型编码介绍如下:

  • latin1:一种重要的编码,是其他编码的基础
  • cp1252:Microsoft指定的lantin1超集
  • cp437:IBM PC最初的字符集,包含框图符号
  • gb2312:用于编码简体中文的陈旧标准
  • utf-8:目前Web中最常见的8位编码,与ASCII兼容
  • utf-16le:UTF-16的16位编码方案的一种形式

4.4 了解编解码问题

4.4.1 处理UnicodeEncodeError

多数非UTF编解码器只能处理Unicode字符的一小部分子集。把文本转换成字节序列时,如果目标编码中没有定义某个字符,那就会抛出UnicodeEncodeError异常,除非把errors参数传递给编码方法或函数,对错误进行特殊处理。如下例所示:

>>> city="北京"
>>> city.encode('utf-8')
b'\xe5\x8c\x97\xe4\xba\xac'
>>> city.encode('gb2312')
b'\xb1\xb1\xbe\xa9'
>>> city.encode('cp437')
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    city.encode('cp437')
  File "G:\Python\lib\encodings\cp437.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-1: character maps to <undefined>
>>> city.encode('cp437',errors="ignore")
b''
>>> city.encode('cp437',errors='replace')
b'??'
>>> city.encode('cp437',errors="xmlcharrefreplace")
b'&#21271;&#20140;'

当cp437无法编码汉字时,抛出UnicodeEncodeError。
对error参数的设置说明如下:

  • ignore:悄无声息地跳过无法编码的字符串
  • replace:将无法编码的字符替换成‘?’
  • xmlcharrefreplace:把无法编码的字符替换成XML实体

4.4.2 处理UnicodeDecodeError

不是每一个字节都包含有效的ASCII字符,也不是每一个字符序列都是有效的UTF-8或UTF-16。因此,把二进制序列转换成文本时,如果假设是这两个编码中的一个,遇到无法转换的字节序列时会抛出UnicodeDecodeError。如下例:

>>> octets=b'Montr\xe9al'
>>> octets.decode('cp1252')
'Montréal'
>>> octets.decode('iso8859_7')
'Montrιal'
>>> octets.decode('koi8_r')
'MontrИal'
>>> octets.decode('utf-8')
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    octets.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte
>>> octets.decode('utf-8',errors='replace')
'Montr�al'

不同的编解码器将相同的字节解码成不同的字符,对于utf-8解码器,抛出异常。

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

Python3默认使用UTF-8编码源码。GNU/Linux和OS X系统大都使用UTF-8编码,因此打开Windows系统中使用cp1252编码的.py文件时可能发生报错。
为修正此问题,可在文件顶部添加一个神奇的coding注释

# coding: utf-8

python允许在源码中使用非ASCII标识符,这意味着变量名,函数名等可以是中文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值