Python 多种中文乱码问题原因及解决方法(decode()、encode()、raw_input())

Python 多种中文乱码问题一直困扰大多数初学者,特别是在Python2中很难解决,通过多次遇到乱码问题的总结,以及查询到的相关资料和解决方法,本文主要介绍总结一下Python 中文乱码问题原因及解决方法,以及decode()、encode()、raw_input()方法编码相关问题介绍。

1、字符编码

字符编码(英语:Character encoding)也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。

1)ASCII

美国(国家)信息交换标准(代)码,一种使用7个或8个二进制位进行编码的方案,最多可以给256个字符(包括字母、数字、标点符号、控制字符及其他符号)分配(或指定)数值。

ASCII码于1961年提出,用于在不同计算机硬件和软件系统中实现数据传输标准化,在大多数的小型机和全部的个人计算机都使用此码。ASCII码划分为两个集合:128个字符的标准ASCII码和附加的128个字符的扩充和ASCII码。比较EBCDIC。其中95个字符可以显示。另外33个不可以显示。 标准ASCII码为7位,扩充为8位。

目前使用最广泛的西文字符集及其编码是 ASCII 字符集和 ASCII 码( ASCII 是 American Standard Code for Information Interchange 的缩写),它同时也被国际标准化组织( International Organization for Standardization, ISO )批准为国际标准。

2)GB2312

GB2312 也是ANSI编码里的一种,对ANSI编码最初始的ASCII编码进行扩充,为了满足国内在计算机中使用汉字的需要,中国国家标准总局发布了一系列的汉字字符集国家标准编码,统称为GB码,或国标码。其中最有影响的是于1980年发布的《信息交换用汉字编码字符集 基本集》,标准号为GB 2312-1980,因其使用非常普遍,也常被通称为国标码。GB2312编码通行于我国内地;新加坡等地也采用此编码。几乎所有的中文系统和国际化的软件都支持GB 2312。

3)GBK

GBK即汉字内码扩展规范,K为扩展的汉语拼音中“扩”字的声母。英文全称Chinese Internal Code Specification。GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,1980年由国家标准总局发布。基本集共收入汉字6763个和非汉字图形字符682个,通行于中国大陆。新加坡等地也使用此编码。GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样)。

4)Unicode

如上ANSI编码条例中所述,世界上存在着多种编码方式,在ANSi编码下,同一个编码值,在不同的编码体系里代表着不同的字。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,可能最终显示的是中文,也可能显示的是日文。在ANSI编码体系下,要想打开一个文本文件,不但要知道它的编码方式,还要安装有对应编码表,否则就可能无法读取或出现乱码。为什么电子邮件和网页都经常会出现乱码,就是因为信息的提供者可能是日文的ANSI编码体系和信息的读取者可能是中文的编码体系,他们对同一个二进制编码值进行显示,采用了不同的编码,导致乱码。这个问题促使了unicode码的诞生。

如果有一种编码,将世界上所有的符号都纳入其中,无论是英文、日文、还是中文等,大家都使用这个编码表,就不会出现编码不匹配现象。每个符号对应一个唯一的编码,乱码问题就不存在了。这就是Unicode编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6C49。

Unicode固然统一了编码方式,但是它的效率不高,比如UCS-4(Unicode的标准之一)规定用4个字节存储一个符号,那么每个英文字母前都必然有三个字节是0,这对存储和传输来说都很耗资源。

5)UTF-8

为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。

UTF-8的编码是这样得出来的,以”汉”这个字为例:

“汉”字的Unicode编码是U+00006C49,然后把U+00006C49通过UTF-8编码器进行编码,最后输出的UTF-8编码是E6B189。

2、.py文件编码问题

报错信息Non-ASCII character '\xe4' in file demo.py on line 1, but no encoding declared;

问题原因:一般报这个错误时,我们使用print sys.getdefaultencoding()输出一下Python默认编码,一般这种情况默认编码都是ASCII,而ASCII不能识别\xe4,所以会报错。根据上面字符编码可知,ASCII 编码是不能表示汉字中文的。

解决方法.py文件头加上# encoding:utf-8,存储.py文件时以utf-8编码,就不会乱码了。

示例代码如下:

# encoding:utf-8
import sys
print sys.getdefaultencoding()
s = "中文乱码问题解决"
print repr(s)

注意:编码声明注释写成# -*- coding: utf-8 -*-也可以,只要满足正则表达式^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)

3、Python IDE中正常面CMD中乱码

CMD 下进入 python 交互模式输出中文是正常的,在Python IDE下输出中文也是正常的,但在CMD中,使用Python file.py方式运行就乱码。

问题原因:这种情况下,在 CMD 或者 Python IDE 中打印字符的时候已经和文件编码方式无关了,问题在于输出环境 CMD 或者 Python IDE的编码方式。

CMD 的编码命令是 chcp,返回 936936 代表 GBK 编码。.py文件存储和编码声明都是utf-8,但CMD 显示编码是 GBK。而将中文的utf-8 编码字符串强制转换为 GBK 就会乱码。

解决方法

1).py文件和编码声明为 GBK,比较麻烦不推荐此方法

例如:

# encoding:gbk
s = "中文乱码问题解决"
print s
print repr(s)

2)在中文前面加上个小写u标记,后面的中文就用 unicode 存储

# encoding:utf-8
s = u"中文乱码问题解决"
print s
print repr(s)

CMD 下使用Python file.py就可以打印 unicode 字符了。

3)中文强制转换为GBK或unicode编码

强制转换为unicode编码,在 Python 中编码是可以互相转换的,如从utf-8转换为gbk,不同编码之间不能直接转换,需要先转成unicode字符集,在转换成其它编码,通过上面字符编码的介绍可知unicode是一种字符集,不属于编码,而utf-8是具体实现unicode的一种编码。utf-8转换为unicode是一种解码过程,通过decode可从utf-8解码成unicode

例如,

# encoding:utf-8
s = "中文乱码问题解决"
u = s.decode('utf-8')
print u
print type(u)
print repr(u)

强制转换为gbk编码,从utf-8转换为unicode后,从unicode是编码的过程,通过encode实现。

例如,

# encoding:utf-8
s = "中文乱码问题解决"
u = s.decode('utf-8')
g = u.encode('gbk')
print g
print type(g)
print repr(g)

注意:Windows CMD 窗口下不支持utf-8,显示中文必须转换为gbk或者unicode,而 Python IDE 中这三种编码都支持。中文乱码的出现都是由于编码不一致导致的,存储的是用utf-8,打印输出用gbk就会乱码了,所有要保证不乱码尽量保持统一,建议使用unicode

4、decode() 解码

其它编码变成unicode叫解码,decode()方法可以实现解码,第一个参数为被解码的字符串原始编码格式,

例如,

# encoding:utf-8
s = "中文"
u = s.decode('utf-8')
#不能指定错编码格式,否则会报错。
#u = s.decode('gbk')
print u
print repr(u)

注意:有些情况下,两个中文字符判断是相等的,但于换了运行环境,导制两个字符串编码不一致,可能出现意外的情况下,需要注意一下。

5、encode() 编码

不能直接从utf-8转换为gbk,需要经过unicode中间转换,被编码的原始字符串一定要为unicode,否则会报错。

例如,

# encoding:utf-8
s = "中文乱码问题解决"
#直接执行s.encode('gbk')会报错,需要执行.decode('utf-8')转换成unicode后,在执行encode()
u = s.decode('utf-8')
g = u.encode('gbk')
print g
print type(g)
print repr(g)

6、raw_input()

raw_input 作用是获取用户输入,获取到的用户输入和当前运行环境编码有关,如 CMD 下默认编码是 gbk,则输入的汉字就是以gbk编码,而不管.py 文件编码格式和编码声明。

例如,

# encoding:utf-8
s = raw_input(u"输入中文字符: ")
print s
print type(s)
print repr(s)

注意:文件存储为utf-8格式,编码声明为utf-8# encoding:utf-8,出现汉字的地方前面加 u,不同编码之间不能直接转换,要先转成unicode,然后从unicode转成其它编码。

推荐阅读
cjavapy编程之路首页