Python字符编码

在编写Python程序时经常会遇到乱码问题,如果搞不清楚编码问题就会晕头转向,如果搞清楚编码问题就会迎刃而解。

首先什么是字符编码,我们知道计算机中存储的数据都是0和1,显然不能把字符存进去,因此就把字符和数字对应起来,用数字代替字符存到存储介质中,而数字与字符的映射关系就是编码表。美国人最先制定了ASCII编码表,里面定义了字母、数字和其他一些常用字符的编码,编码数字范围为0~127。

但是问题来了,ASCII码表给英文用是足够了,但是没办法表示其他语言,所以针对不同的语言就产生了很多不同的编码,例如俄文编码集是KOI8、法文编码集是Latin1、中文的则是GBK,但是这样很不方便,尤其是假如在一份文档中包含几种语言的字符,这样就没法统一编解码了。

为了解决这一问题 Unicode 应运而生,Unicode编码集合了世界上的所有字符,这样就解决了编码不统一的问题,但是Unicode并不完美:它太浪费空间了,并且伴随着其他一些存储和传输上的缺陷。

基于此 UTF-8 出现了,它解决了 Unicode 的问题,而且像 Unicode 一样包含了所有字符,‘UTF’ 就是 ‘Unicode Transformation Format’ 的简写。目前 UTF-8 是世界最通用的编码格式。

在说 Python 中的编解码前先声明几个概念:
encoding: 由 Unicode 字符串转化为 字节串的过程叫 encoding
decoding: 由 字节串转化为 Unicode 字符的过程叫 decoding, 正好与 encoding 相反。

Unicode 编码称为抽象,而各个编码格式称为 Unicode 的实现,各个不同的编码实现都可以通过 Unicode 进行相互转换。
这里写图片描述

看懂这幅图中的关系就OK了。

下面进入正题说 Python 中的字符编码问题:
Py2 和 Py3 之间的编码做了很大的改动,先说Py3:
Py3 中的字符串 str 类型即为 Unicode, Unicode 经过编码得到的字节串即为 bytes, Py3 中的默认编码格式为 UTF-8, 而要编码为其他编码格式则要显示指定,也就是说:

In [1]: str1 = '嘿嘿'

In [2]: utf8_str = str1.encode()

In [3]: gbk_str = str1.encode(encoding='gbk')

In [4]: utf8_str
Out[4]: b'\xe5\x98\xbf\xe5\x98\xbf'

In [5]: gbk_str
Out[5]: b'\xba\xd9\xba\xd9'

In [6]: 

解码要与当初编码的方式一致,否则就会报错或者乱码。

In [6]: utf8_str.decode()
Out[6]: '嘿嘿'

In [7]: gbk_str.decode('gbk')
Out[7]: '嘿嘿'

In [8]: gbk_str.decode()
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-9-627ffed75053> in <module>()
----> 1 gbk_str.decode()

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xba in position 0: invalid start byte

In [9]: 

Py2的 str 就是字节串,在 str 字面量的前面加上 ‘u’ 就标示这是个 Unicode 串, 与 Python3 相反。Py2 源文件运行时对字符串字面量的编码方式默认为 ASCII 码,因此在 Py2 源文件中直接写中文会报错

str1 = '哈哈'

执行这个 python 文件会报错:SyntaxError: Non-ASCII character ‘\xe5’ in file py2_t.py on line 1, but no encoding declared
在 Py2 源文件的最开始加上 # -*- coding: <encoding name> -*-,指定源代码中的字符串字面量的编码方式:

# -*- coding:utf-8 -*-

str1 = '哈哈'

print str1

但是在 Python2 中的 encoding、decoding 方法默认编码方式依然是 ASCII, 可以通过这个来修改程序的默认编码:

import sys

reload(sys)
sys.setdefaultencoding('utf-8')

以上我们只是指定了程序运行内部的默认编码方式,在对文件进行读写时,就不只涉及程序的编码方式了。
在进行文件操作时,Py2 的字符串就是字节,读进来的是字节,写出去的也是字节,如果要写入一个 Unicode 串,则会用当前程序的默认编码方式编码后再写入,open 函数中的 mode 参数 加不加 ‘b’ 都是无所谓。
而 Py3 就不一样了,读写文件要区分 mode, 加 ‘b’ 的只能传 bytes, 不加 ‘b’ 的只能传 Unicode 串,加 ‘b’ 的情况很简单,就是直接读写字节串:

with open('yourfilename', 'rb') as f:
    f.read()  #得到bytes对象
with open('yourfilename', 'wb')as f:
    f.write(data)  #data必须是 bytes 对象

而如果是不加 ‘b’ 的情况,读写的数据必须是 Py3 字符串,而且会被编解码,根据当前的操作系统环境,而不是根据当前 python 程序的默认编码格式,如何查看当前操作系统的默认编码格式:

import locale

locale.getpreferredencoding()

默认 UNIX/Linux、Mac 是 UTF-8, windows 是gbk, 所以在Linux上运行的 python 程序读取一个 gbk 编码格式的文件,会报错:

#Linux 环境下运行

with open('yourfilename', 'r') as f:
    f.read()  #按 UTF-8 解码

所以读取不同编码格式的文件数据需要指定编码方式:

with open('yourfilename', 'r', encoding='gbk'):
    f.read() #按 gbk 解码

同样,写入文件时如果不指定编码,会写入成功,但是文件可能会乱码。

Python3 对编码进行了改进,问题主要在 Python2, 要记住 Python2 中 str 是字节,u’hello’ 这种是 Unicode 串。任何编码方式的数据都可以通过 Unicode 进行转换。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值