Quantcast
Channel: CodeSection,代码区,Python开发技术文章_教程 - CodeSec
Viewing all articles
Browse latest Browse all 9596

真是个撩人的小妖精!谈谈python的编码问题

$
0
0

上两天编写了个小工具程序,读取文件信息并输出适当数据到控制台。程序本身没什么难度,但是编码问题确实恶心到我了。同样的程序,在mac下跑没问题,在windows下跑就有问题;在pycharm上面的终端上跑没问题,到系统自带的terminal上面跑又有问题。真是哔了狗了呀!

简单搜索下就可以发现在python下面确实很多人遇到或者曾经遇到过python的这个编码问题。


真是个撩人的小妖精!谈谈python的编码问题

作为程序员,你一定遇到过中文编码的问题。

windows cmd 下 print 会把字符串转换成 gbk 编码来输出,所以才会有 LZ 现在遇到的问题。

编码基础

就像不同的国家使用不同的语言一样,小猪面对不会中文的同学时也是一脸懵逼。计算机也是一样,不同的地区使用不同的语言,而计算机只认识0和1。怎么让这些0和1显示成人能理解的字符呢?

首先登场的是ASCII码。

ASCII

ASCII码,每一个字符都会对应一个ASCII码,占一个字节,早期的电脑是美国人发明的,所以最开始的时候ASCII码是只有127个的。例如0123456789a-zA-Z。发展到中国的时候,原本的这些ASCII码显然已经不够用了,所以中国制定了GB2312码,占两个字节。

可是这只解决了中文的问题,那韩文日文法文怎么办呢?每个国家都制定一个编码?那一个语言的输出到另外的国家的编码里显然会出现了所谓的乱码。所以,编码真是个让人头疼的问题啊。尤其是在编写python2程序的时候。

为了解决上述问题,另外一个名词就出现了:Unicode,占用两字节,目前大多数操作系统都支持该编码。

Unicode

Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字 ― 维基百科

字母A用ASCII编码是二进制的 01000001 ,十进制的65;

字符0用ASCII编码是二进制的 00110000 ,十进制的48,注意字符’0’和整数0是不同的;

汉字中已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。

你可以猜测,如果把ASCII编码的A用Unicode编码,只需要在前面补0就可以,因此,A的Unicode编码是00000000 01000001。

所以,Unicode其实是包含了ASCII码的表示范围的,只是如果ASCII码在不够使用的情况下使用Unicode来表示。在使用Unicode码的时候,本身能够使用ASCII码的数据只需在前面补足一个字节的00000000就可以了。

可是在早期的计算机系统当中,存储数据的空间是非常昂贵的。虽然是满足了所有字符能够表示的问题,但是多出来毫无意义的一个字节也是要占用空间的。

这个时候又出现了我们经常提到用到的 UTF-8 编码.

UTF-8

他就是所谓的变长编码,当表示的字符能够用一个字节来表示是,他就占用一个字节,当当前字符需要使用两个字节的空间来表示时,他就占用两个字节,特殊情况下可能用到三个字节甚至四个字节。

所以在计算机的内存中,是使用0和1的ASCII码,当存储到硬盘或者需要显示的时候,程序将其转换成对应的UTF-8码。

python的编码

python可是在Unicode发布之前就已经出身了。所以他出身之后的事情在出身时当然是不知道的。

所以python2的默认编码为ascii,python3的默认编码为utf-8

>>> importsys >>> sys.getdefaultencoding() 'ascii'

python提供了内置函数来查看字符的ASCII码!

>>> ord('Z') 90 >>> chr(90) 'Z'

在后来的版本中,python提供了对Unicode的支持,但是必须要在字符的前面加上字母u:

>>> print(u"小猪") 小猪 >>> u"小猪" u'\u5c0f\u732a' >>> "小猪" '\xe5\xb0\x8f\xe7\x8c\xaa' >>> u"小猪".encode('utf-8') '\xe5\xb0\x8f\xe7\x8c\xaa' u'\u5c0f\u732a'.encode('utf-8') '\xe5\xb0\x8f\xe7\x8c\xaa' >>> '\xe5\xb0\x8f\xe7\x8c\xaa'.decode('utf-8') u'\u5c0f\u732a'

所以,字符 u'\u5c0f\u732a' 和 u"小猪" 对python来说是一样的。但是对于只看输出结果的 人 来说就不一样了,所以才会出现文章一开始的时候提到的让小猪头疼的输出乱码问题。

上面代码的第三部分是把字符’小猪’当做utf-8来打印了。所以在使用utf-8来decode的时候能够解析出来 u'\u5c0f\u732a'

一般我们需要在python文件的开头标识当前文件使用哪个编码格式:

#!/usr/bin/env python # -*- coding: utf-8 -*-

这样在打印中文的时候就不会报错:

print("小猪") # SyntaxError: Non-ASCII character '\xe5' in file /Users/smallerpig/Desktop/demo.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

可是在还有一些情况下,例如开头时说的,很多字符是从别的库里面引用进来的,这样我们并不能保证得到的每个字符串的编码都是一致的。这时候就要根据得到的字符的具体的编码来使用decode方法来进行解码然后来显示了。


Viewing all articles
Browse latest Browse all 9596

Trending Articles