前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >浅谈 Python 2 中的编码问题

浅谈 Python 2 中的编码问题

作者头像
Crossin先生
发布于 2018-04-17 01:54:06
发布于 2018-04-17 01:54:06
1K0
举报

Python 2.x 里的编码实在是一件令人烦躁的事情。不断有初学者被此问题搞得晕头转向。我自己也在很长一段时间内深受其害,直到现在也仍会在开发中偶尔被坑。在本教室的提问和讨论中,编码问题也占据了相当大的比重。

然而这个问题并不能一两句话轻易解答。今天在这里稍微分析一下,希望能帮各位理清这里面的问题。

要弄清编码问题,首先明确几个概念:

str、unicode、encode、decode

str

就是我们通常说的字符串,在 python 中是由引号包围的一串字符。但是 Python 中的默认字符并不包括中文及其他复杂字符(其他非英语语言、特殊符号等)。虽然你可以定义"你好"这样的字符串,但在 Python Shell 中输入一下你就会发现:

>>> '你好' '\xe4\xbd\xa0\xe5\xa5\xbd'>>>

在程序中,这两个字符是被其他的一些按照某种格式的普通字符所表示。进一步地,输入:

>>> len('你好') 6

字符串的长度也并不是想象中的2。

这就是我们一直说的编码。即通过某种规定的形式,用一些字符表示另一些字符。目的就是为了用少量的简单字符表示更多更复杂的字符。

上述的结果,是因为我的 Python Shell 里默认使用 UTF-8 对字符进行了编码。如果你在 Windows 下进行尝试,会是不一样的结果,因为 Windows 默认使用的是一种叫做 cp936 的编码。

当你需要通过 Python 得到某些输入或者输出,比如读取网页,输出到控制台,读写文件等等,需要处理的都是 str 类型。所以必然逃不过编码的问题。

unicode

为了处理不同编码的字符,于是有了 unicode。unicode 本身是一种编码,因为足够的长度,它可以包容各种文字和符号。同时它也是 Python 中的一种类型。在表示形式上,是字符串的引号前加上一个 u。比如

>>> u'你好' u'\u4f60\u597d' >>> type(u'你好') <type 'unicode'> >>> type('你好') <type 'str'>

可以看出,unicode 和 str 是两种不同的类型。

虽然 unicode 很强大,但在 Python 2 中,它不能被直接输出,而必须通过某种编码转成 str。

encode & decode

encode 是 unicode 的一种方法,作用是按照某种形式对其进行编码,转为 str。如:

>>> u'你好'.encode('utf-8') '\xe4\xbd\xa0\xe5\xa5\xbd'

decode 是 str 的一种方法,作用是按照某种形式对其进行解码,转为 unicode。如:

>>> '你好'.decode('utf-8') u'\u4f60\u597d'

对 unicode 进行 encode 没太大问题,但对 str decode 时,因为 str 本身是有某种编码的,这时候如果指定的编码不符,就会产生讨厌的乱码:

>>> '你好'.decode('cp936') u'\u6d63\u72b2\u30bd' >>> print '你好'.decode('cp936') 浣犲ソ

在默认的 utf-8 编码环境下强行使用 cp936 编码,就会出现乱码。

小结一下就是:

输入 -> str -> decode -> unicode -> encode -> str -> 输出

那么通常问题出在哪里呢?

一般情况下,我们在程序里做的只是

输入 -> str -> 逻辑处理 -> str -> 输出

但在输入输出过程和中间的逻辑处理时,很可能 Python 帮我们默认做了一些 encode 和 decode 的工作。比如说,print 会按照环境的默认形式进行编码,当在需要 unicode 类型的操作而程序拿到的是一个 str 类型是,会使用 ascii 进行解码。前者将可能导致乱码显示,而后者就直接报错。

举两个例子:

1

程序从网上抓取一段网页,中间的文字是 gbk 编码,如 '\xbb\xb6\xd3\xad'(欢迎)。但抓取下来,从默认 utf-8 控制台输出时,就变成了 ��ӭ。同理存在于,Windows 下抓取了 utf-8 编码的网页。正确的处理方法是手动做一次解码:

>>> s = '\xbb\xb6\xd3\xad' >>> print s ��ӭ >>> s.decode('gbk') u'\u6b22\u8fce' >>> print s.decode('gbk') 欢迎

2

程序有一段从输入得到的 cp936 编码文字,如 '\xd5\xc5\xc8\xfd'(张三),和从数据库取出的 unicode 字符串,如 u'\u597d\u4eba'(好人),两者需要做拼接时:

>>> a = '\xd5\xc5\xc8\xfd' >>> b = u'好人' >>> a + b Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xd5 in position 0: ordinal not in range(128)

抛出了经常发生的 UnicodeDecodeError 异常。这是因为在 str 和 unicode 做 + 操作时,会自动将 str 转成 unicode,并且使用了 ascii 编码。同样的问题也会发生在对一个 str 对象直接使用 encode 的时候。比如:

>>> a = '\xd5\xc5\xc8\xfd' >>> a.encode('utf-8')

原因也是一样,encode 是 unicode 类型的方法,对 str 进行调用时,程序会默认先直接试图用 ascii 编码把 str 转成 unicode。

正确的做法:

>>> a.decode('cp936') + b u'\u5f20\u4e09\u597d\u4eba' >>> a.decode('cp936').encode('utf-8') '\xe5\xbc\xa0\xe4\xb8\x89'

另外还有个要注意的地方是,Python 代码的 py 文件默认是是用 ascii 编码,所以在程序里有中文的时候,需要在文件开头指定编码,例如:

# coding: utf-8

有些 IDE 比如 PyScripter 会另外设置你的文件编码,有时还会有冲突。

要注意搞清:

程序文件本身的编码 - 你在程序里赋值的字符串

输入来源的编码 - 获取的变量值

输出环境的编码 - 控制台、文件、网页

最好能保证这几个的一致性,不一致时也要做好相应的转换,才能避免掉进编码的坑。

最后,为巴黎恐怖袭击中的遇难者以及所有战争的受害者哀悼。本教室有不少身处国外的读者,各位注意自身安全。愿大家都平安。

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

本文分享自 Crossin的编程教室 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
关于 Python3 的编码
对应 C 代码为:unicodeobject.c 中的 _Py_normalize_encoding 函数。
py3study
2020/01/03
1.7K0
手撕Python之文件操作
打开文件,open(文件路径,mode='r',encodeing='cp936')
凯子坚持C
2024/09/23
930
手撕Python之文件操作
Python3 里不存在编码问题?
编码问题在 Python 中一直是个巨坑。关于 Python 2 的编码问题,之前写过一篇文章: 浅谈 Python 2 中的编码问题 在 Python 3 中,编码问题得到了改进,str 类型直接使
Crossin先生
2018/04/17
6900
Python3 里不存在编码问题?
str、bytes和bytearray编码
str是字符数据,bytes和bytearray是字节数据。它们都是序列,可以进行迭代遍历。str和bytes是不可变序列,bytearray是可变序列,可以原处修改字节。
狼啸风云
2019/12/10
1.4K0
str、bytes和bytearray编码
python 字符编码处理总结
python中经常遇到这样那样的字符编码问题,尤其在处理网页源码时(特别是爬虫中):
昱良
2018/09/29
6130
python的str,unicode对象的encode和decode方法
python的str,unicode对象的encode和decode方法  python中的str对象其实就是"8-bit string" ,字节字符串,本质上类似java中的byte[]。  而python中的unicode对象应该才是等同于java中的String对象,或本质上是java的char[]。  对于 
bear_fish
2018/09/20
2K0
Python 蛋疼的编码问题
Python 的编码问题早就困扰我太久了, 但一直没有看到比较通俗易懂的专门介绍 Python 编码问题的文章。 正好今天刷知乎看到了非常不错的文章, 这里稍微抛砖引玉归纳下。
Ewdager
2020/07/14
8280
Python 蛋疼的编码问题
The Encode and Decode in Python
Do you really know the encode and decode in Python?
timerring
2025/02/10
880
Python 编码转换与中文处理
python 中的 unicode是让人很困惑、比较难以理解的问题. 这篇文章 写的比较好,utf-8是 unicode的一种实现方式,unicode、gbk、gb2312是编码字符集.
bear_fish
2018/09/19
3.6K0
python2/3中 将base64数据写成图片,并将图片数据转为16进制数据的方法、bytes/string的区别
python 3中最重要的新特性可能就是将文本(text)和二进制数据做了更清晰的区分。文本总是用unicode进行编码,以str类型表示;而二进制数据以bytes类型表示。
用户1214487
2018/09/27
2.2K0
python2/3中 将base64数据写成图片,并将图片数据转为16进制数据的方法、bytes/string的区别
基础知识:字符编码
1、什么实字符编码:将人识别的字符转换成计算机能识别的01,而转换的过程或者规则就是字符编码表。
py3study
2020/01/17
5150
Unicode,GBK和UTF-8
看到题目,你也许会说,“又是这种月经帖,这问题我早弄清楚了”. 但如果有人问你,“Unicode,GBK和UTF-8有什么区别?”, 你能自信地给他一句简短清晰的回答吗? 如果不能的话, 那还是看一下
evilpan
2023/02/12
1.6K0
Unicode,GBK和UTF-8
Python3与Python2的具体区别
有赞的数据库管控平台是基于Python 2(py2)开发的,目前已经升级到python3(py3) 版本,主程序基于python 3.6.x。写本文是梳理一下 两个版本之间的语法,函数等差异。
用户1278550
2020/08/04
8540
Python3.7中文字符编码问题
最近在尝试 Python Web方面的开发尝试,框架使用的是Django,但是在读取数据库并页面展示的时候,出现了中文编码的问题。
小柒2012
2019/12/05
1.7K0
编码-2
之前的一篇文章对一些基本的python编码问题做了比较表面的解释,有兴趣的可以点击这里去看一下我对python编码的基础理解。好了,下面先提出我碰到的问题。
py3study
2020/01/06
5210
字符串的这个东西-翻译表
不知道大家是否见过这个东西,反正我清楚记得我是见过的,可是为什么会写这个东西?有以下一个场景: 怎样将一个字符串中的中文字符统一转换成英文字符? 不知道大家会怎样去做?先列举一个例子: 'hello
py3study
2020/01/02
1.1K0
python中的encode()和decode()函数
对于很多人来说,python的中字符转码是一件很头疼的事情,本来期望结果输出的是中文,结果来一段像这样\xe4\xbd\xa0\xe5\xa5\xbd像是乱码的字符串。
全栈程序员站长
2022/11/08
1.1K0
python中的encode()和decode()函数
字符、字符集、编码,以及它们python中会遇到的一些问题(下)
在看了很多的博客文章之后,总结整理得到了以下文章,非常感谢这些无私奉献的博主! 文章末尾有本文引用的文章的链接,如果有漏掉的文章引用,可以发邮件联系我,随后再次附上链接! 侵删!!! 这一部分是下篇,主要讲的是编码部分,以及在python中会遇到的一些编码问题,偏向于实际应用一点。 上篇介绍了字符、字符集的一些概念,以及他们在python中的一些简单的代码示例,偏向于概念。 上篇地址:http://www.cnblogs.com/echo-coding/p/7435118.html 这绝对是个源
Echo_fy
2018/06/20
2K0
详解Python字符串编码格式
最早的字符串编码是美国标准信息交换码ASCII,仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASCII采用1个字节来对字符进行编码,最多只能表示256个符号。 随着信息技术的发展和信息交换的需要,各国的文字都需要进行编码,不同的应用领域和场合对字符串编码的要求也略有不同,于是又分别设计了多种不同的编码格式,常见的主要有UTF-8、UTF-16、UTF-32、GB2312、GBK、CP936、base64、CP437等等。UTF-8编码是国际通用的编码,以1个字节表示英语字
Python小屋屋主
2018/04/16
1.8K0
python 字符串(字符序列)和字节序列
字符序列(string) -> 字节序列(bytes) -------------编码(encode)
友儿
2022/09/26
6250
相关推荐
关于 Python3 的编码
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文