前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >讲明白python令人头疼的编码问题

讲明白python令人头疼的编码问题

作者头像
哒呵呵
发布2018-08-06 15:14:05
1K0
发布2018-08-06 15:14:05
举报
文章被收录于专栏:鸿的学习笔记鸿的学习笔记

计算机可见的只是字节序列,人类可读的只有文本。

在python3里,已经做了区分unicode就是文本,bytes就是原始的字节序列。

字节,码位,字节表述:

--字符的标识(码位):是0到1114111的数字,在unicode的标准中以4~6个十六进制数字表示,以'u+'表示。

--字符的具体表述是取决于所用的编码(在码位和字节序列之间的转换的算法),比如‘我’这个单词,

代码语言:javascript
复制
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知,

代码语言:javascript
复制
a[0]
Out[13]: 230

可以看出二进制序列实则是整数序列,显示的时候就会以三种方式显示:

-可打印的ascii范围内的字节(从空格到~),使用ascii字符本身

-制表符,换行符,回车符和\对应的字符,使用转义序列\t,\n,\r和\\

-其它字节的值使用十六进制转义序列(\x00是空字节)

如下:

代码语言:javascript
复制
'我\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种解编码器,我们可以看看:

代码语言:javascript
复制
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,

代码语言:javascript
复制
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:这种出现的问题,可能出产生无用的输出,解码方式错了的话,或者说产生乱码。

代码语言:javascript
复制
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参数

代码语言:javascript
复制
a.decode('utf8',errors = 'replace')
Out[24]: 'mon?al'

其他的解码呢?

代码语言:javascript
复制
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文档,不同系统的编码。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档