python中文编码乱码问题

转载 2018年04月17日 14:07:04

转自:https://blog.csdn.net/ggggiqnypgjg/article/details/53271541


背景

多次被python的编码/乱码问题困扰,相信pythoner们都被困扰过,网上铺天盖地的资料太多也参差不齐,就整理了下。本文从使用的角度系统总结了python编码相关的一些概念,将本文的例子玩一遍,基本上对python的编码问题就清楚了。

首先明确几个概念:

  1. 字节流:以utf8/gbk等编码编码的字节流。
  2. unicode对象:python代码中,a=u'中国', 或者a='中国'.decode()的结果。
  3. terminal用于显示字符的编码:将一个用utf8/gbk编码的字节流通过terminal指定的编码,去查找对应的字符显示出来。
  4. locale:linux下,Locale 是软件在运行时的语言环境, 它包括语言(Language), 地域 (Territory) 和字符集(Codeset)。一个locale的书写格式为: 语言[_地域[.字符集]]. 所以说呢,locale总是和一定的字符集相联系的。比如:zh_CN.GB2312
  5. 编码转换原则:unicode是”中介”,任何编码之间转换都需要先decode()到unicode。

针对python,先把结论放在前面,三点:

  1. #coding:utf-8 #.py文件是什么编码就需要告诉python用什么编码去读取这个.py文件。
  2. sys.stdout.encoding,默认就是locale的编码,print会用sys.stdout.encoding去encode()成字节流,交给terminal显示。所以locale需要与terminal一致,才能正确print打印出中文。
  3. sys.setdefaultencoding(‘utf8’),用于指定str.encode() str.decode()的默认编码,默认是ascii。 
    • 对编码字符串a,代码中可以直接写a.encode(“gbk”),但事实上内部自动先通过defaultencoding 去decode成unicode之后再encode()的。
    • str(xxx)应该也是用这个去编码的。
    • 'ascii' codec can't encode characters in position 7-8: ordinal not in range(128)print的时候出现这个错误一般可以使用这个方案去处理。
    • 为了避免代码中到处都要去encode(“xxx”),还有可能不同的地方写得不一样带来不一致的情况,推荐使用这个:
import sys   
reload(sys)   
sys.setdefaultencoding('utf8')   
  • 1
  • 2
  • 3

例子1:

  • 在python中,unicode vs 字节流:字节流可以从unicode encode得到,unicode可以从utf8/gbk等编码的字节流decode得到。
  • 分析下面这段代码,终端/locale分别为不同编码的情况:
#coding:utf-8              #由于.py文件是utf-8的,所以必须有这一句
import sys
import locale
import os
import codecs

reload(sys)
print sys.getdefaultencoding() + "  - sys.getdefaultencoding()"
sys.setdefaultencoding('utf8')                  #影响encode()
print sys.getdefaultencoding() + "  - sys.getdefaultencoding()"

print sys.stdout.encoding + " - sys.stdout.encoding:"
#sys.stdout = codecs.getwriter('utf8')(sys.stdout)    #影响print
print sys.stdout.encoding + " - sys.stdout.encoding:"

u = u'中国'
print u + "  - u"
a = '中国'
print a + " - a"
print a.decode('utf-8') + " - a.decode('utf-8')"
print a.decode('utf-8').encode('gbk') + "   - a.decode('utf-8').encode('gbk')"
print a.decode('utf-8').encode('utf-8') + " - a.decode('utf-8').encode('utf-8')"
print a.decode('utf-8').encode() + "    - a.decode('utf-8').encode()"

print (sys.stdout.encoding) + " - (sys.stdout.encoding)"
print (sys.stdout.isatty())
print (locale.getpreferredencoding())
print (sys.getfilesystemencoding())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

—终端为UTF-8,locale为zh_CN.GBK—————–

ascii  - sys.getdefaultencoding()
utf8  - sys.getdefaultencoding()
GBK - sys.stdout.encoding:
GBK - sys.stdout.encoding:
�й�  - u
中国 - a
�й� - a.decode('utf-8')
�й�   - a.decode('utf-8').encode('gbk')
中国 - a.decode('utf-8').encode('utf-8')
中国    - a.decode('utf-8').encode()
GBK - (sys.stdout.encoding)
True
GBK
utf-8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

—终端为UTF-8,locale为zh_CN.UTF-8—————–

ascii  - sys.getdefaultencoding()
utf8  - sys.getdefaultencoding()
UTF-8 - sys.stdout.encoding:
UTF-8 - sys.stdout.encoding:
中国  - u
中国 - a
中国 - a.decode('utf-8')
�й�   - a.decode('utf-8').encode('gbk')
中国 - a.decode('utf-8').encode('utf-8')
中国    - a.decode('utf-8').encode()
UTF-8 - (sys.stdout.encoding)
True
UTF-8
utf-8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

—终端为GBK,locale为zh_CN.GBK—————–

ascii  - sys.getdefaultencoding()
utf8  - sys.getdefaultencoding()
GBK - sys.stdout.encoding:
GBK - sys.stdout.encoding:
中国  - u
涓???? - a
中国 - a.decode('utf-8')
中国   - a.decode('utf-8').encode('gbk')
涓???? - a.decode('utf-8').encode('utf-8')
涓????    - a.decode('utf-8').encode()
GBK - (sys.stdout.encoding)
True
GBK
utf-8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

—终端为GBK,locale为zh_CN.UTF-8—————–

ascii  - sys.getdefaultencoding()
utf8  - sys.getdefaultencoding()
UTF-8 - sys.stdout.encoding:
UTF-8 - sys.stdout.encoding:
涓????  - u
涓???? - a
涓???? - a.decode('utf-8')
中国   - a.decode('utf-8').encode('gbk')
涓???? - a.decode('utf-8').encode('utf-8')
涓????    - a.decode('utf-8').encode()
UTF-8 - (sys.stdout.encoding)
True
UTF-8
utf-8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

例子1总结,对print而言:

  • unicode的数据如果要显示正常,必须终端与locale一致。sys.stdout.encoding这个值应该来自locale,print会以sys.stdout.encoding去encode并输出到字节流。
  • encode为终端编码的字节流就能显示正常,无论locale是啥。 
    最终是terminal通过terminal配置的编码规则去解码成对应的字符并显示出来。

例子2:

关于sys.setdefaultencoding(‘utf8’)的例子:

#coding:utf-8
import sys

reload(sys)
sys.setdefaultencoding('utf8')
print sys.getdefaultencoding() + "  - sys.getdefaultencoding()"

a = '中国'
print a + " - a"
print a.encode("gbk")  #并不是直接从utf8的字节流转化到gbk的,而是通过defaultencoding decode之后才转的。
print a.decode() #使用默认的defaultencoding
print a.encode() #使用默认的defaultencoding
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

关于str()和repr()

  • str()是对各种类型转化成str,如果本来是encoded字符串,则不变,如果为unicode,会encode()
  • repr()对字符串是将字节流出二进制的值以16进制转化为可见字符。 
    测试环境locale为GBK
#coding:utf-8

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

a = u'中国'
print a
print str(a)
print repr(a)
print repr(a.encode("utf-8"))
print repr(a.encode("gbk"))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
中国
涓????
u'\u4e2d\u56fd'
'\xe4\xb8\xad\xe5\x9b\xbd'
'\xd6\xd0\xb9\xfa'
  • 1
  • 2
  • 3
  • 4
  • 5

再深挖下去,还有repr()和eval()的关系,就不深挖了。

关于终端和服务器的编码

另外补充一些关于终端和服务器编码的结论: 
1. 对mac iterm2,如果server的locale与mac本地终端的locale一致,才能保证server端与本地的表现一致。 
2. cat a.py #就把文件显示出来,就是给terminal一串字节流。terminal根据设置的终端编码规则来显示字符。所以只要文件编码与terminal一致即可,与locale无关。 
3. cat a.txt > b.txt #无论locale怎么样,只跟a.txt原来的编码相关 
4. echo “中国年过” > a.txt #这个情况下,只有terminal与locale的编码一致,你才能在终端shell打出正确的中文~~~所以a.txt与两者都会一致

参考资料

关于vim:http://blog.chinaunix.net/uid-21843387-id-106001.html


【Python】第二周Python基础(下)

-
  • 1970年01月01日 08:00

QRCode二维码支持中文

  • 2013年05月21日 15:19
  • 3KB
  • 下载

SourceInsight4.082

  • 2017年02月24日 17:18
  • 1.2MB
  • 下载

Python2.7.13中文乱码问题

欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和...
  • qq_29200921
  • qq_29200921
  • 2017-07-16 10:33:41
  • 1324

中文编码乱码问题

一个字符变成2个乱码字符 一个汉字变成一个问号 中文字符变成了不能处理中文字符的ISO-8859-1编码 变成了3f 解码以后就变成了? 一个汉字变成了2个问号 中文经过了gbk编码以...
  • wb453178064
  • wb453178064
  • 2016-07-08 13:30:02
  • 162

Python发送Http请求时,中文乱码问题的解决方法

解决python http请求中文乱码问题。
  • yuhentian
  • yuhentian
  • 2017-10-05 23:27:34
  • 382

python解决中文编码问题

python解决中文编码问题    摘要:因为这段时间做python的中文数据梳理和爬虫,中文数据处理花费了我大量的时间,暂时不做这一块所以留下一些记录。为了快速完成文章,这里对很多文章进行了引用和摘...
  • xz1308579340
  • xz1308579340
  • 2017-04-19 16:41:47
  • 2943

python3的matplotlib中文乱码问题(数据是中文的情况)

Matplotlib是Python的一个很好的绘图包,但是其本身并不支持中文(貌似其默认配置中没有中文字体),所以如果绘图中出现了中文,就会出现乱码。 下面给出个例子解决中文乱码问题: i...
  • u010442302
  • u010442302
  • 2018-01-22 15:37:47
  • 92

python中文编码详解

部分转自:http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html 编码的历史 1.     ASCII ASCII(Ameri...
  • inte_sleeper
  • inte_sleeper
  • 2011-08-10 16:50:14
  • 9981

JAVAIO编码的乱码问题和解决办法

先做一个相关说明,文件是采用byte存储的,文本是采用某种编码的char数组,文本文件是采用某种编码的字符数组采用字节的形式存储的。  好了,了解以上这些就好办了,下面进入正题吧。 下面通过文...
  • Hello_gays
  • Hello_gays
  • 2016-07-31 19:38:07
  • 237
收藏助手
不良信息举报
您举报文章:python中文编码乱码问题
举报原因:
原因补充:

(最多只允许输入30个字)