python 中文乱码问题学习
python的IDLE编辑代码使用中文,运行程序乱码,对此很苦恼,于是搜索解决方法
彻底搞懂 python 中文乱码问题
中文乱码实例讲解
我们来说说 Python 中是如何存储字符的,先来看一个乱码的例子。新建一个 demo.py 文件,文件存储格式为utf-8
文件中内容如下。
s = "中文"
print s
在 cmd 中运行 python demo.py
,什么,我只是想打印中文
两个字居然给我报错,简直不可理喻啊!
赶紧打开 python 自带的 idle 试试看,一点问题都没有啊,这是为什么呢?
回头好好看看 cmd 下报的错误Non-ASCII character '\xe4' in file demo.py on line 1, but no encoding declared;
,翻译过来就是 在 demo.py 文件的第 1 行有非 ASCII 字符 ‘\xe4’,而且没有声明编码,从上面基础知识可知,ASCII 编码是不能表示汉字中文的,demo.py 文件第一行有中文两个汉字,而 demo.py 文件存储格式为utf-8
,所以中文两个汉字在文件中存储的时候是以 utf-8
编码存储的,查看 demo.py 文件 16 进制可以看到中文 存储的是 \xe4\xb8\xad\xe6\x96\x87
。
16 进制查看用的是 notepad++ 自带的 HEX-Editor 插件,另外函数 repr
也能显示原始字符串,如下。
# encoding:utf-8
import sys
print sys.getdefaultencoding()
s = "中文"
print repr(s)
sys.getdefaultencoding()
读取 python 默认编码是 ASCII,而 ASCII 是不认识 \xe4
的,所以会报错Non-ASCII character '\xe4' in file demo.py on line 1, but no encoding declared;
,此时只要在 demo.py 文件头加上 # encoding:utf-8
就可以了,虽然是注释,但 python 看到这句话就知道了接下来应该用utf-8
编码了,而 demo.py 存储时也是utf-8
的,所以就正常了。
# encoding:utf-8
s = "中文"
print s
编码声明注释写成
# -*- coding: utf-8 -*-
也是可以的,只要满足正则表达式^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)
就OK。
我们再次在 cmd 下运行 python demo.py 试试看。
啥,啥,啥,说好的显示中文呢?这不是逗我吗?去 python idle 下试试看。
为什么同样的文件在 python idle 中却正常呢?肯定是 cmd 有问题,是的,我也是这样想的,那我试着在 cmd 下进入 python 交互模式输出中文看看,我去居然 cmd 下也是可以正常输出 中文的,相信看到这里小伙伴们都已经晕了。
别急,听我慢慢分析。其实当在 cmd 或者 idle 中打印字符的时候已经和文件编码方式没有关系了,此时起作用的是输出环境也就是 cmd 或者 idle 的编码方式有关,查看 cmd 的编码命令是 chcp
,返回 936,去网上查找可知 936 代表 GBK
编码,这下我们大概知道什么原因了,demo.py 文件存储和编码声明都是utf-8
,但是 cmd 显示编码是 GBK
,而将中文
的utf-8
编码 \xe4\xb8\xad\xe6\x96\x87
强制转换为 GBK
就会乱码了,GBK
是两个字节存储一个中文字符,所以 \xe4\xb8\xad\xe6\x96\x87
会解码成三个字,很不幸这三个字涓枃
不是常用字也不是我们想要的字符,所以就认为是乱码了。为什么在 cmd 下进入 Python 交互式命令行可以呢,这是因为当在 python 交互式命令行输入s = "中文"
时,中文
这两个汉字其实是以 GBK
编码存储的,cmd 默认编码是 GBK
,不信看s
打印\xd6\xd0\xce\xc4
,这就是GBK
编码方式存储,而utf-8
编码方式存储同样的中文
为\xe4\xb8\xad\xe6\x96\x87
。下面告诉大家怎么解决在 cmd 下执行文件正确输出中文问题。
1、demo.py 文件和编码声明都为 GBK
这种方法比较笨,就是把 demo.py 文件改为 GBK
存储,而且编码声明也是GBK
,个人不推荐。
# encoding:gbk
s = "中文"
print s
print repr(s)
2、中文用 unicode 表示
只要在中文前面加上个小u
标记,后面的中文就用 unicode
存储了。
# encoding:utf-8
s = u"中文"
print s
print repr(s)
cmd 下是可以打印 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 idle 中这三种编码都支持。中文乱码的出现都是由于编码不一致导致的,存储的是用utf-8
,打印的时候用gbk
就会乱码了,所有要保证不乱码尽量保持统一,建议全部使用unicode
。
decode 解码
从其它编码变成unicode
叫解码,解码用的方法是decode
,第一个参数为被解码的字符串原始编码格式,如果写错了也会报错。比如 s 是utf-8
,用gbk
去解码就会报错。
# encoding:utf-8
s = "中文"
u = s.decode('gbk')
print u
print repr(u)
小提示 在 Python idle 和 cmd 下直接输入 s = "中文"
会以 gbk
编码的,如果在文件中输入 s = "中文"
且文件存储格式为utf-8
,那么 s 是以utf-8
编码存储的,有点不一样曾经踩过坑,及时 Python idle 成功了文件运行的时候也可能失败。
encode 编码
不可以直接从utf-8
转换为gbk
,必须经过unicode
中间转换,这点很重要,被编码的原始字符串一定要为unicode
,否则会报错。
raw_input
raw_input 是获取用户输入值的,获取到的用户输入值和当前运行环境编码有关,比如 cmd 下默认编码是 gbk
,那么输入的汉字就是以gbk
编码,而不管 demo.py 文件编码格式和编码声明。
# encoding:utf-8
s = raw_input("input something: ")
print s
print type(s)
print repr(s)
GBK 编码一个汉字两个字节,UTF-8 一个汉字通常3个字节。
细心的朋友已经注意了,raw_input
的提示语我用的是英文,那改成中文看看,果真出现乱码了。
# encoding:utf-8
s = raw_input("请输入中文汉字:")
print s
print type(s)
print repr(s)
怎么办呢?把提示字符串强制为gbk
编码就好,unicode
和utf-8
都不可以。
# encoding:utf-8
s = raw_input(u"请输入中文汉字:".encode('gbk'))
print s
print type(s)
print repr(s)
相等陷阱
“中文”这两个字符串用不同的编码存储是不一样的,utf-8
编码和gbk
编码存储的“中文”都不一样。
总结
一口气说了这么多,不知道你们看懂没?想要不乱码,记住以下5点法则就好。
- 文件存储为
utf-8
格式,编码声明为utf-8
,# encoding:utf-8
- 出现汉字的地方前面加
u
- 不同编码之间不能直接转换,要经过
unicode
中间跳转 - cmd 下不支持
utf-8
编码 raw_input
提示字符串只能为gbk
编码