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

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

在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文档,不同系统的编码。

原文发布于微信公众号 - 鸿的学习笔记(shujuxuexizhilu)

原文发表时间:2017-08-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java工会

Java基础第一阶段知识点,招实习的面试官都在问这些

a) 答:Java源文件被编译成字节码的形式,无论在什么系统环境下,只要有java虚

1331
来自专栏好好学java的技术栈

“面试不败计划”: java语言基础面试题(二)

962
来自专栏LinkedBear的个人空间

唠唠SE的面向对象-12——访问修饰符 原

963
来自专栏用户2442861的专栏

Python补充11 序列的方法 正则表达式 (re包)

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

771
来自专栏Web行业观察

一张图撸明白prototype原型链

expression instanceof class expression和class都是必选项。

3164
来自专栏我是攻城师

Java基础类String了解一下

当你路过一些商场或者地铁口的时候,有没有被千篇一律的"xx健身,了解一下" 所烦到。

1132
来自专栏Java帮帮-微信公众号-技术文章全总结

JAVA面试题解惑——final、finally和finalize的区别

final、finally和finalize的区别是什么? 这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、final...

3556
来自专栏我的技术专栏

漫谈C++:良好的编程习惯与编程要点

1257
来自专栏java工会

Java基础第一阶段知识点,招实习的面试官都在问这些

2199
来自专栏浪淘沙

关于队列的几个小算法

  思路 :创建3个变量,start,end,size; size用来查看数组中数据的数量,从而实现添加和删除的长度控制。当添加数据时,如果end=size-...

1493

扫码关注云+社区

领取腾讯云代金券