Python程序在Windows终端乱码解决方法

简介:

问题提出


近期把一个Python项目移到了Windows下运行,竟然中文乱码了,在Linux上运行明明好好的。

Python程序在Windows终端乱码

呵呵,对Windows妥妥的没有爱了。。。。

问题原因


Python程序在Windows终端(cmd)下乱码,是字符串编码的问题

Python文件编码


Python 默认脚本文件都是 ANSCII 编码的,当文件 中有非 ANSCII 编码范围内的字符的时候就要使用”编码指示”来修正。 一个module的定义中,如果.py文件中包含中文字符(严格的说是含有非anscii字符),则需要在第一行或第二行指定编码声明:

# -*- coding=utf-8 -*-
  • 1
  • 1

或者

#coding=utf-8
  • 1
  • 1

其他的编码如:gbk、gb2312也可以; 否则会出现类似

SyntaxError: Non-ASCII character '/xe4' in file ChineseTest.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html  for details
  • 1
  • 1

这样的异常信息

实际上Python只检查#、coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8。参见http://docs.python.org/library/codecs.html#standard-encodings

另外需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心 :)

系统默认的编码方式可以采用:

import sys
print sys.getdefaultencoding( )
  • 1
  • 2
  • 1
  • 2

当然设置默认的编码方式采用:

import sys
reload(sys)
print sys.setdefaultencoding('utf-8')
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

至于为什么要reload sys,是因为系统在加载时删除了sys.setdefaultencoding(’utf-8’)这句,所以这个时候要重新加载reload sys模块才能调用sys.setdefaultencoding(’utf-8’)语句起作用
基础就这么多了,接下来我们再看看字符串的编码。。。。

str和unicode编码


str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。
str类型是一个包含Characters represent (at least) 8-bit bytes的序列;unicode的每个unit是一个unicode obj
所以:len(u’中国’)的值是2;len(‘ab’)的值也是2;

在str的文档中有这样的一句话:The string data type is also used to represent arrays of bytes, e.g., to hold data read from a file. 也就是说在读取一个文件的内容,或者从网络上读取到内容时,保持的对象为str类型;如果想把一个str转换成特定编码类型,需要把str转为Unicode,然后从unicode转为特定的编码类型如:utf-8、gb2312等;

对UTF-8编码的str’汉’使用len()函数时,结果是3,因为实际上,UTF-8编码的’汉’ == ‘\xE6\xB1\x89’。
unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u’汉’) == 1。

例如下面的代码

#coding=utf-8

import sys
if __name__ == "__main__"
    print sys.getdefaultencoding( )    #  默认编码为ascii

    s1 = '中文'
    print type(s1)      #  str[UTF-8编码]
    print len(s1)       #  6
    print s1            #  乱码

    s2 = u'中文'       #  unicode
    print type(s2)      #  2
    print len(s2)       # 
    print s2            #  异常,UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
                        #  s2的编码为unicode,而当前文件的编码为utf-8,Python内置默认编码为ascii
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

再来看看encode()和decode()两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:

encode和decode


参考Python字符编码详解

首先,现存有很多种编码方式,就中文而言,gb2312,GBK,gb18030(包含中文字符最多最全面的)
而目前国际上常用的编码方式有:utf-8.(发现中文乱码之后,百度答案:在py文件开头添加coding为utf-8)

-*- conding: utf-8 -*-
 xxx.decode()  是把xxx按括号中的编码方式  解码成unicode
 xxx.encode()  是把unicode类型的xxx按括号中的编码方式  进行编码(所
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

以如果xxx不是unicode,系统会采用默认编解码方式对xxx进行解码,然后再做如上的编码操作)
下面我们看几个转换编码的例子

unicode转为 gb2312,utf-8等

#coding=utf-8

#unicode转为 gb2312,utf-8等

if __name__ == "__main__":
    s = u'中国'
    s_gb = s.encode('gb2312')
    print s_gb
    #  utf-8,GBK转换为unicode 使用函数unicode(s,encoding) 或者s.decode(encoding)

    s = u'中国'
    #s为unicode先转为utf-8
    s_utf8 =  s.encode('UTF-8')
    assert(s_utf8.decode('utf-8') == s)
    print s_utf8.decode('utf-8')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

普通的str转为unicode

#coding=utf-8


import sys
#  普通的str转为unicode
if __name__ == '__main__':

    #  如果把下面几行注视掉会异常
    print sys.getdefaultencoding( )
    reload(sys)
    sys.setdefaultencoding( "utf-8" )
    print sys.getdefaultencoding( )


    s = '中国'
    su = u'中国'
    print s         #  乱码
    print su        #  不乱码
    #s为unicode先转为utf-8

    #  因为s为所在的.py(# -*- coding=UTF-8 -*-)文件编码应该为utf-8
    #  采用sys.setdefaultencoding( "utf-8" )设置字符编码为utf-8
    s_unicode =  s.decode('UTF-8')
    assert(s_unicode == su)
    print s_unicode

    #s转为gb2312, 需要先转为unicode再转为gb2312

    print s.decode('utf-8').encode('gb2312')

    #如果直接执行s.encode('gb2312')会发生什么?

    print s.encode('gb2312')
  • 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
  • 29
  • 30
  • 31
  • 32
  • 33
  • 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
  • 29
  • 30
  • 31
  • 32
  • 33

对比

#coding=utf-8

import sys

if __name__ == '__main__':
    s = '中国'
    print s
    #如果直接执行s.encode('gb2312')会发生什么?
    print s.encode('gb2312')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这里会发生一个异常:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
  • 1
  • 1

Python 会自动的先将 s 解码为 unicode ,然后再编码成 gb2312。因为解码是python自动进行的,我们没有指明解码方式,python 就会使用 sys.defaultencoding 指明的方式来解码。很多情况下 sys.defaultencoding 是 ANSCII,如果 s 不是这个类型就会出错。
拿上面的情况来说,我的 sys.defaultencoding 是 anscii,而 s 的编码方式和文件的编码方式一致,是 utf8 的,所以出错了: UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe4 in position 0: ordinal not in range(128)
对于这种情况,我们有两种方法来改正错误:
一是明确的指示出 s 的编码方式

#! /usr/bin/env python 
# -*- coding: utf-8 -*- 
s = '中文' 
s.decode('utf-8').encode('gb2312') 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

二是更改 sys.defaultencoding 为文件的编码方式

#coding=utf-8

import sys

if __name__ == '__main__':

    reload(sys)
    sys.setdefaultencoding( "utf-8" )
    s = '中国'
    print s
    #如果直接执行s.encode('gb2312')会发生什么?
    print s.encode('gb2312')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Pyton内部编码

首先要搞清楚,字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

在某些IDE中,字符串的输出总是出现乱码,甚至错误,其实是由于IDE的结果输出控制台自身不能显示字符串的编码,而不是程序本身的问题。

#coding=utf-8

import sys 

if __name__ == "__main__":
#  该文件的编码必需与s.decode('utf8')指定的编码一致,不然会抛出解码异常信息,
#  可以通过s.decode("gbk", "ignore")或s.decode("gbk", "replace")来解决。

    print sys.getdefaultencoding( )    #  默认编码为ascii
    s = '中文'

    # 该文件的编码为UTF-8, 因此无异常
    s.decode('utf8')            #  将默认的unicode编码字符解码成utf8
    print s

    #  异常UnicodeDecodeError: 'gbk' codec can't decode bytes in position 2-3: illegal multibyte sequence
    #s.decode('GBK')             #把unicode类型串的s按括号中GBK的编码方式,编码成GBK
    #print s

    # 异常UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
    #s.encode('GBK')
    #print s

    s.decode('gbk', "ignore")   #  将s按照gbk编码解码为utf8,忽略其中有异常的编码,仅显示有效的编码
    print s
    s.decode('gbk', 'replace')  #  替换其中异常的编码,这个相对来可能一眼就知道那些字符编码出问题了
    print s
  • 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
  • 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

该文件的编码必需与s.decode(‘utf8’)指定的编码一致,不然会抛出解码异常信息

文件编码与print函数


建立一个文件test.txt,文件格式用ANSI,内容为:

abc中文
  • 1
  • 1

用如下python代码来读取

#coding=gbk
print open("Test.txt").read()
  • 1
  • 2
  • 1
  • 2

结果输出

abc中文
  • 1
  • 1

把文件格式改成UTF-8:
结果:

abc涓枃
  • 1
  • 1

显然,这里需要解码

# coding=gbk
import codecs
print open("Test.txt").read().decode("utf-8")
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

结果:

abc中文
  • 1
  • 1

上面的test.txt我是用Editplus来编辑的,但当我用Windows自带的记事本编辑并存成UTF-8格式时,
运行时报错:

Traceback (most recent call last):
  File "ChineseTest.py", line 3, in <module>
    print open("Test.txt").read().decode("utf-8")
UnicodeEncodeError: 'gbk' codec can't encode character u'/ufeff' in position 0: illegal multibyte sequence
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

原来,某些软件,如notepad,在保存一个以UTF-8编码的文件时,会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM)。
因此我们在读取时需要自己去掉这些字符,python中的codecs module定义了这个常量:

# coding=gbk
import codecs
data = open("Test.txt").read()
if data[:3] == codecs.BOM_UTF8:
 data = data[3:]
print data.decode("utf-8")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

结果:

abc中文
  • 1
  • 1

总结


Windows下终端输出中午的方法

明确的指示出 s 的编码方式下输出中文


#coding=utf-8
import sys
if __name__ == "__main__":

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

    # 下面两种代码等价
    print "中文".decode("utf-8")
    print u"中文"
    assert("中文".decode("utf-8") == u"中文")


    # 下面两种代码等价
    print "中文".decode("utf-8").encode("GBK")     #  将字符先解码成utf8,在编码成GBK
    print u"中文".encode("GBK")   # u"XXX"定义的字符为unicode字符,直接将unicode编码的字符编码为GBK编码,然后输出

    #  同上
    print "中文".decode("utf-8").encode('gb2312')
    print u"中文".encode('gb2312')

    print "中文".decode("utf-8").encode('cp936')
    print u"中文".encode('cp936')

    print u'中文'.encode('utf-8').decode('utf-8')


    #如果直接执行s.encode('gb2312')异常
    print "中国".encode('gb2312')
  • 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
  • 29
  • 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
  • 29

或者

更改sys.defaultencoding为文件的编码方式下输出中文


这种方式下上面所用的输出方法同样适用

#coding=utf-8
import sys
if __name__ == "__main__":

    #  当字符串的编码不是utf-8
    print sys.getdefaultencoding( )
    reload(sys)
    sys.setdefaultencoding( "utf-8" )
    print sys.getdefaultencoding( )


    #如果直接执行s.encode('gb2312')
    print "中国".encode('gb2312')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

小结


解决方法:

1.直接使用 u’中文’ 形式,指明以unicode编码,解码方式会以顶部 #coding定义的编码方式,如果不写,以操作系统当前编码方法,建议写上#coding,因为要让操作系统编码和源文件编码经常会不一样。推荐使用这种方式

2.输出时指定解码方法 print ‘是’.decode(“utf8”) ,必须和保存的编码一致,忽略#coding的定义

3.将#coding 和保存编码改为和操作系统一样的编码,就可以直接print ‘是’ 正常输出,也不推荐,因为需要事先知道操作系统编码,复制到其他电脑上,操作系统编码不一样就会出错


转载:http://blog.csdn.net/gatieme/article/details/45648167

目录
相关文章
|
11天前
|
Python
python魔法方法如何应用
【4月更文挑战第12天】这个Python示例展示了类继承和方法重写。`Student`类继承自`Person`,并覆盖了`say_hello`方法。通过`super().__init__(name)`调用父类的`__init__`初始化`name`属性,`Student`添加了`age`属性,并在重写的`say_hello`中使用。创建`Student`实例`student`并调用其`say_hello`,输出定制的问候信息。
19 1
|
13天前
|
消息中间件 编译器 API
Windows窗口程序
Windows窗口程序
|
15天前
|
人工智能 机器人 C++
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
【C++/Python】Windows用Swig实现C++调用Python(史上最简单详细,80岁看了都会操作)
|
4天前
|
数据采集 JavaScript 前端开发
使用Python打造爬虫程序之破茧而出:Python爬虫遭遇反爬虫机制及应对策略
【4月更文挑战第19天】本文探讨了Python爬虫应对反爬虫机制的策略。常见的反爬虫机制包括User-Agent检测、IP限制、动态加载内容、验证码验证和Cookie跟踪。应对策略包括设置合理User-Agent、使用代理IP、处理动态加载内容、验证码识别及维护Cookie。此外,还提到高级策略如降低请求频率、模拟人类行为、分布式爬虫和学习网站规则。开发者需不断学习新策略,同时遵守规则和法律法规,确保爬虫的稳定性和合法性。
|
4天前
|
存储 关系型数据库 MySQL
Python搭建代理IP池实现存储IP的方法
Python搭建代理IP池实现存储IP的方法
|
4天前
|
Python
Python动态IP代理防止被封的方法
Python动态IP代理防止被封的方法
|
5天前
|
数据采集 存储 安全
python检测代理ip是否可用的方法
python检测代理ip是否可用的方法
|
5天前
|
SQL 安全 Go
如何在 Python 中进行 Web 应用程序的安全性管理,例如防止 SQL 注入?
在Python Web开发中,确保应用安全至关重要,主要防范SQL注入、XSS和CSRF攻击。措施包括:使用参数化查询或ORM防止SQL注入;过滤与转义用户输入抵御XSS;添加CSRF令牌抵挡CSRF;启用HTTPS保障数据传输安全;实现强身份验证和授权系统;智能处理错误信息;定期更新及审计以修复漏洞;严格输入验证;并培训开发者提升安全意识。持续关注和改进是保证安全的关键。
11 0
|
6天前
|
数据可视化 测试技术 Python
在Python和R中使用交叉验证方法提高模型性能
在Python和R中使用交叉验证方法提高模型性能
|
6天前
|
存储 监控 开发工具
对象存储OSS产品常见问题之python sdk中的append_object方法支持追加上传xls文件如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
36 9