盒子
盒子
文章目录
  1. 1. 默认编码变化
  2. 2. str与bytes
  3. 3. 参考资料

Python3 编码

由于Python3编码方面的内容变化很多,所以重新写一篇文章来讨论一下。也当成自己学习的记录了。

编码?你需要知道的那些事:1-了解字符集

编码?你需要知道的那些事:2-明白编码

编码?你需要知道的那些事:3-Python2.x为什么有乱码

编码?你需要知道的那些事:4-Java为什么有乱码

更新

Python3 编码

The rules for translating a Unicode string into a sequence of bytes are called an encoding.
Unicode字符串转换成字节序列的规则被称为编码。

之前的文章里面提到过,Python2.x默认的编码是ascii(因为当初Python诞生的时候,还没有Unicode,具体的看之前文章),这也是为什么我们讨论在Python2.x中出现乱码的情况。

1. 默认编码变化

在Python3中,默认编码变为了utf-8,我们可以进行验证。

1
2
3
import sys
sys.getdefaultencoding()
Out[2]: 'utf-8'

这样我们在使用print函数、读取文件、保存文件时,Python3默认都会使用utf-8进行编码。

下面做一个测试。

Screen Shot 2017-08-29 at 20.30.59
这是一个使用GB 18030(也是一类GBK编码标准,主要是增加了汉字数量)编码保存的文件,我们在Python中使用默认方式打开会出现什么结果呢?

WX20170829-203515@2x

都不让打开,直接报错,肯定的毕竟UTF-8和GBK不兼容。正确方式如下:

1
2
3
f = open('gbk.txt', 'r', encoding='gbk')
f.read()
Out[59]: '这个测试文件'

看来,是和GBK说再见的时候了(尽量少用),如果都使用默认编码的话一般不会再出现乱码问题了。

下面介绍utf-8编码的规则和好处。

  1. utf-8进行编码的规则:

    • 如果Unicode码位(编号)< 128,则由相应的字节值表示。
    • 如果Unicode码位(编号)> = 128,将它变成两个,三个或四个字节的序列,其中序列的每个字节都在128到255之间。
  2. 使用utf-8进行编码的好处(半翻译):

    • 它可以处理任意Unicode码位(编号)。

    • 将一个Unicode字符串变成一个不包含嵌入零字节的字节序列。

    • 一串ASCII文本也是有效的UTF-8文本(具有兼容性)。

    • UTF-8相当紧凑,大多数常用字符可以用一个或两个字节表示(节省内存)。

    • 如果字节损坏或丢失,可以确定下一个UTF-8编码代码点的开始并重新同步。

2. str与bytes

Python2.x中,字符串有两种表现类型:一个是Unicode(表示文本字符串)、一个是str(表示字节序列)。

在Python3.x中,使用str表示字符串,bytes表示字节序列。官方文档是这样介绍的:

  • str (字符)

    Strings are immutable sequences of Unicode code points.

    str是一串不可变的Unicode码位(编码)序列。

  • bytes(字节)

    bytes is an immutable sequence of integers in the range 0 <= x < 256.

    bytes是一串不可变的整数(0 <= x < 256)序列。

下面这张图可以一定程度上说明区别。

WX20170829-205039@2x

现在我们定义一个str字符,它默认就是一个Unicode的字符。

1
2
3
duigou = '✓' # 定义字符
ord(duigou) # 获取字符在Unicode中的码位
Out[18]: 10003 # 码位

上面输出的10003(十六进制表示为0x2713)正是对钩字符在Unicode中的编号(码位)。

现在我们使用utf-8编码将字符编码为字节:

1
2
3
4
5
duigou.encode('utf-8') # 编码 或者 bytes(s, encoding='utf-8')
Out[20]: b'\xe2\x9c\x93' # 输出,注意utf-8是变长编码
type(b'\xe2\x9c\x93') #查看type
Out[30]: bytes

可以看出✓字符使用utf-8编码后是三个字节,如果使用GBK进行编码呢?

1
2
3
4
5
6
7
duigou.encode('gbk')
---------------------------------------------------------------------------
UnicodeEncodeError Traceback (most recent call last)
<ipython-input-27-3cbb798ed584> in <module>()
----> 1 duigou.encode('gbk')
UnicodeEncodeError: 'gbk' codec can't encode character '\u2713' in position 0: illegal multibyte sequence

我x,怎么出错了? 不会啊,思路没有错啊,将Unicode的字符编码为字节呢。 其实,不出错才不正常呢,因为GBK字符集中没有这个字符。

如果我们知道了一个字符的Unicode编号,怎么将它变为字符呢?好问题。

比如有一个粗实心心。它的编号(码位)是10084,我们使用下面代码将它变为一个字符(注意:GBK中没有这个字符)。

WX20170829-210900@2x

1
2
3
cushixinxin = 10084 #Unicode编号
chr(cushixinxin) #chr函数
Out[29]: '❤' #输出,粗实心心

下面是上面使用到的两个函数的原型:

  • ord(c)

    Given a string representing one Unicode character, return an integer representing the Unicode code point of that character.

  • chr(i)

    Return the string representing a character whose Unicode code point is the integer i.

3. 参考资料

Python3变化

Unicode HOWTO

支持一下
扫一扫,支持forsigner