Python3.x编码详解和在cmd运行环境中打印字符串print乱码或报错
如果使用的是python2.x就不用往下看啦,差别太大。网上很多python的文章写的时候都没有注明是3.x还是2.x的版本很坑
问题描述
使用python时经常遇到类似报错UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1
python3对文本以及二进制数据做了比较清晰的区分。在代码中赋值给变量的文本总是Unicode,由str类型进行表示,二进制数据使用bytes进行表示,不会将str与bytes偷偷的混在一起,使得两者的区别更加明显。
python3字符串编码说明
python2和3部分改动区别
#!/usr/bin/env python # -*- coding: utf-8 -*-
上面第二行是告诉解释器读取源代码的时候用utf-8编码读取
下面这个是python2设置默认编码方式使用的,python3里默认就是utf8所以不用设置并且上面那一行声明也可以省略
sys.setdefaultencoding('utf8')
字符串在Python3内部(源代码中直接赋值的文本)表示统一用unicode编码,python3中写字符串用下面两种方式是一样的结果都是unicode编码,也就是说在默认情况下,被引号框起来的字符串,都是使用Unicode编码的。
注意:你从本地文本或网络上读过来的文本赋值给变量,编码跟上面可不一样,可能是utf8、gbk等等 ,这点一定要分清楚
s1="你好" s2=u"你好"
非Unicode编码格式的文本来源:从网络抓取的网页/第三方/硬盘/其它等来源的字符串可能是比如UTF-8、GBK,这些编码方式,得到这些数据时一般都是字节流,用什么编码转换就看你知不知道它的编码喽!可以使用 chardet去检查下文本的编码然后进行处理再显示
疑惑的地方
python3默认编码为utf8,赋值字符串时默认编码为unicode。似乎不一至啊?
这两个不冲突,
默认编码utf8是使用py代码编码解码字符串没有传指定编码参数时使用的默认编码,
unicode是源代码里赋值给变量字符串时使用的编码,直接放入内存!可以说是内存编码
Python涉及到编码的地方
py源代码的编码
你写源代码时使用的编码是什么,比如中文windows记事本默认的gbk2312的
编辑器使用哪种编码显示源代码的
比如用词本写源代码再用pycharm打开源代码可能就会乱码,因为pycharm默认是用utf-8显示的
运行界面显示文本的编码(重要)
这个编码搞不清楚就问题大啦,就会报各种错误,大家肯定遇到过一个脚本在pycharm下运行正常,但到cmd下运行就出问题的情况吧。
pycharm的运行环境编码为utf-8
cmd的运行环境编码为gbk,
cmd下可以使用chcp命令查看活动页的编码,简体中文系统中显示为936
936 GBK(一般情况下为默认编码)
437 美国英语
65001 utf-8
当使用print向运行界面打印信息时,是把这个字符串用默认编码转化成对应的的字节给运行界面显示的,如果你给的字符串编码是unicode的那么系统会自动根据环境转成对应的gbk或utf8去显示但是如果你给的是utf-8然后丢给cmd显示cmd默认是界面gbk的编码字符,这个时候print就会报错啦
比如远程抓取一个utf-8网页的代码,
import urllib.request #url url="http://www.baidu.com" #请求 request = urllib.request.Request(url) #爬取结果 response = urllib.request.urlopen(request) s = response.read() s=s.decode('utf8') print(s)
直接在pycharm中输出正常,但在cmd中输出时就报错啦如下:
'gbk' codec can't encode character '\xbb' in position 27226: illegal multibyte sequence
看报错内容应该是print打印的时候运行界面环境是什么编码它就会把字符串再编码成什么格式的字符集然后再给界面显示,上面请求的是utf8的字符串,需要再编码成gbk再给界面,自然就出错啦(具体原因涉及到python的标准输出流sys.stdout自行研究吧)
下面一个解决方法,放在代码开始的地方就可以
#如果运行环境是gbk if sys.stdout.encoding == 'cp936': #改变标准输出的默认编码 sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')
读入文本时的编码
从本地硬盘远程网页等读入的文本是用字符流读进去的不会报错,但一但使用print(默认是用utf-8)打印的时候打印界面编码跟文本编码不正确,可能就会错啦,这个时候如果知道文本编码就进行下转换不知道的话可以使用 chardet去检查下文本的编码然后进行处理再显示
写出文本时的编码
如果想将文本直接以unicode码保存到文件,用encode(‘unicode-escape’)转化为bytes,写入文件。
如果想将文本以utf-8形式保存到文件,用encode(‘utf-8’)转化为utf-8编码的bytes,写入文件。