乱码这个问题困扰了包括我在内的很多人,现在我来梳理一下。
首先我们可以在SHELL中查看一下自己默认的编码方式:
>>> import sys现在我知道了我自己默认的编码方式是ASCII(我用的是Windows系统)。接下来我们尝试一下,如果我们在脚本中编写程序,加入中文注释后执行“运行”(Run Module),你会发现系统一直提示你需要保存,原因是你根本无法保存你的脚本文件!
>>> sys.getdefaultencoding()
'ascii'
你在脚本文件的第一行加上 #-*-coding:utf-8-*- 再试试。
这就是由于编码方式不同导致的问题,我们来看下这三种编码方式有何不同:
ASCII码:用一个字节表示一个字符,一个字节8位,所以表示的范围是0-255,比如用65来表示‘A’字符,显然ASCII码并不能表示中文,一个汉字至少需要两个字节,于是产生了
Unicode码。
Unicode码:基本上是用两个字节表示一个字符,比如用00000000 01000001表示字符‘A’,01001110 00101101表示字符‘中’,这样就解决了中文字符的表示方法,但这样的表示方法有它的缺陷,当原文并没有大量的中文字符的时候,就会产生存储空间的浪费,于是产生了可变长度的utf-8码。
utf-8码:utf-8编码把Unicode编码转化为可变长的编码方式,通常英文字符用1个字节,一个中文汉字字符用3个字节,只有很生僻的字符才会用到4-6位的字节。这样的编码方式既能编写ASCII码之外的字符,又能节省存储空间。
Python内部使用的是Unicode编码方式,Python支持encode()编码函数和decode()解码函数,它们的关系如下图:
decode() encode()
String1 ——————> Unicode ——————> String2
我们用一段程序来看看相同的字符串在不同的编码方式下的结果:
#-*-coding:utf-8-*-运行的结果是这样的:
import sys
print(sys.getdefaultencoding())
#原字符串
string= "曾小贤 zxx"
print(string)
#将字符串解码成Unicode编码
str_unicode1 = repr(string.decode('utf8'))
str_unicode2 = string.decode('utf8')
print str_unicode1
print str_unicode2
#用utf8编码
str_utf8 = repr(str_unicode2.encode('utf8'))
print str_utf8
#用gbk编码
str_gbk = repr(str_unicode2.encode('gbk'))
print str_gbk
#用ascii编码
str_ascii = repr(str_unicode2.encode('ascii','ignore'))
print str_ascii
ascii对以上结果的几点说明:
曾小贤 zxx
u'\u66fe\u5c0f\u8d24 zxx'
曾小贤 zxx
'\xe6\x9b\xbe\xe5\xb0\x8f\xe8\xb4\xa4 zxx'
'\xd4\xf8\xd0\xa1\xcf\xcd zxx'
' zxx'
1、repr()函数:repr()函数显示的是对Python解释器显示的效果,如果不加repr()函数,用print()函数打印出来的仍然是原字符串的内容,如print str_unicode2;
2、为什么在用gbk,utf-8编码的时候使用的是str_unicode2而不是1? 因为如果用repr()函数处理后的结果(str_unicode1),实质上仍然是对解码后获得的字符串编码,而不是对原文编码,结果就像下面这样:
"u'\\u66fe\\u5c0f\\u8d24 zxx'"3、为什么用ascii编码后没有显示中文对应的编码?因为ascii里面根本就没有对中文字符编码的支持呀,所以用“ignore”参数忽略了无法编码的部分。
"u'\\u66fe\\u5c0f\\u8d24 zxx'"
4、使用Python3的同学就不用担心乱码问题了。
希望以上过程使您对编码方式有一定的理解。