计算机可见的只是字节序列,人类可读的只有文本。
在python3里,已经做了区分unicode就是文本,bytes就是原始的字节序列。
字节,码位,字节表述:
--字符的标识(码位):是0到1114111的数字,在unicode的标准中以4~6个十六进制数字表示,以'u+'表示。
--字符的具体表述是取决于所用的编码(在码位和字节序列之间的转换的算法),比如‘我’这个单词,
a = '我'.encode('utf8')
Out[10]: b'\xe6\x88\x91'
len(a)
Out[11]: 3
len('我')
Out[12]: 1
这样就用utf8编码中,编码成了三个字节,但是在unicode中只有一个字节。
简而言之,把字节序列变成文本就是解码(decode),文本变成字节序列就是编码(encode)。
在python3中,bytes的各个元素都是介于0-255之间的整数,查看上述变量a知,
a[0]
Out[13]: 230
可以看出二进制序列实则是整数序列,显示的时候就会以三种方式显示:
-可打印的ascii范围内的字节(从空格到~),使用ascii字符本身
-制表符,换行符,回车符和\对应的字符,使用转义序列\t,\n,\r和\\
-其它字节的值使用十六进制转义序列(\x00是空字节)
如下:
'我\tA'.encode('utf8')
Out[16]: b'\xe6\x88\x91\tA'
此外,正则表达式编译自二进制序列而不是字符串,则re模块中的正则表达式函数也能处理二进制序列。
bytes的构造方法,有如下参数:
--str对象和encoding关键字参数
--一个可迭代对象,提供0~255之间的整数
--一个整数,使用空字节创建对应长度的二进制序列
--一个实现了缓冲协议的对象(bytes,bytearray,memoryview,array.array):
ps:https://docs.python.org/3/c-api/buffer.html((简而言之就是,经过包装可以访问底层内存数组或 buffer))
解编码器:
python自带超过100种解编码器,我们可以看看:
for codec in ['gb2312','utf8','utf16']:
print(codec, '我'.encode(codec), sep = '\t')
gb2312 b'\xce\xd2'
utf8 b'\xe6\x88\x91'
utf16 b'\xff\xfe\x11b'
不同编码对中文的解析。
某些编码是不能表示所有字符的,例如latin_1,
UnicodeEncodeError: 'latin-1' codec can't encode character '\u6211' in position 0: ordinal not in range(256)
而utf8的编码的设计目的就是为了处理每一个unicode码位。
处理编码错误
UnicodeEncodeError可以有三种特殊处理的方式,通过errors关键字参数
'我'.encode('latin_1', errors = 'ignore')#忽略掉未编码的问题
Out[19]: b''
'我'.encode('latin_1', errors = 'replace')#将数据替换成'?'
Out[20]: b'?'
'我'.encode('latin_1', errors = 'xmlcharrefreplace')#将数据转换成xml实体
Out[21]: b'我'
UnicodedecodeError:这种出现的问题,可能出产生无用的输出,解码方式错了的话,或者说产生乱码。
a = b'mon\xe9al'
a.decode('utf8')
Traceback (most recent call last):
File "<ipython-input-23-3d146a4c38e4>", line 1, in <module>
a.decode('utf8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3: invalid continuation byte
用utf8就是解码错误,再加上errors参数
a.decode('utf8',errors = 'replace')
Out[24]: 'mon?al'
其他的解码呢?
a.decode('cp1252')
Out[25]: 'monéal'
a.decode('iso8859_7')
Out[26]: 'monιal'
那么谁才是你想要的输出呢?这是个问题
字节序列的编码:
这个需要有人提前的指明,python本身也有Chardet库来检测
BOM:
在utf16编码中,会出现\xff\xfe几个字符,这个就是字节序标记,也就是intel CPU的小字节序,其实就是大端和小端的区别,为了做出这个区别就加上了不可见的特殊字符ZERO WIDTH
NOBREAK SPACE字符。也有显式指定le(小节序列)和be(大节序列)
'我'.encode('utf16')
Out[27]: b'\xff\xfe\x11b'
处理文本的流程大概是:
bytes -> str
100%str
str -> bytes
如果在读取文件时,没有显示的指明你使用的编码字符,便会使用系统默认编码。具体的请参考python文档,不同系统的编码。