python 中文乱码问题深入分析

张开发
2026/4/19 9:10:45 15 分钟阅读

分享文章

python 中文乱码问题深入分析
在本文中以哈来解释作示例解释所有的问题“哈”的各种编码如下1. UNICODE (UTF8-16)C8542 UTF-8E593883 GBKB9FE。一、python中的str和unicode一直以来python中的中文编码就是一个极为头大的问题经常抛出编码转换的异常python中的str和unicode到底是一个什么东西呢在python中提到unicode一般指的是unicode对象例如哈哈的unicode对象为u\u54c8\u54c8而str是一个字节数组这个字节数组表示的是对unicode对象编码(可以是utf-8、gbk、cp936、GB2312)后的存储的格式。这里它仅仅是一个字节流没有其它的含义如果你想使这个字节流显示的内容有意义就必须用正确的编码格式解码显示。例如对于unicode对象哈哈进行编码编码成一个utf-8编码的strs_utf8,s_utf8就是是一个字节数组存放的就是\xe5\x93\x88\xe5\x93\x88但是这仅仅是一个字节数组如果你想将它通过print语句输出成哈哈那你就失望了为什么呢因为print语句它的实现是将要输出的内容传送了操作系统操作系统会根据系统的编码对输入的字节流进行编码这就解释了为什么utf-8格式的字符串“哈哈”输出的是“鍝堝搱”因为 \xe5\x93\x88\xe5\x93\x88用GB2312去解释其显示的出来就是“鍝堝搱”。这里再强调一下str记录的是字节数组只是某种编码的存储格式至于输出到文件或是打印出来是什么格式完全取决于其解码的编码将它解码成什么样子。这里再对print进行一点补充说明当将一个unicode对象传给print时在内部会将该unicode对象进行一次转换转换成本地的默认编码这仅是个人猜测二、str和unicode对象的转换str和unicode对象的转换通过encode和decode实现具体使用如下将GBK哈哈转换成unicode然后再转换成UTF8三、Setdefaultencoding如上图的演示代码所示当把s(gbk字符串)直接编码成utf-8的时候将抛出异常但是通过调用如下代码import sysreload(sys)sys.setdefaultencoding(gbk)后就可以转换成功为什么呢在python中str和unicode在编码和解码过程中如果将一个str直接编码成另一种编码会先把str解码成unicode采用的编码为默认编码一般默认编码是anscii所以在上面示例代码中第一次转换的时候会出错当设定当前默认编码为gbk后就不会出错了。至于reload(sys)是因为Python2.5 初始化后会删除 sys.setdefaultencoding 这个方法我们需要重新载入。四、操作不同文件的编码格式的文件建立一个文件test.txt文件格式用ANSI内容为:abc中文用python来读取# codinggbkprint open(Test.txt).read()结果abc中文把文件格式改成UTF-8结果abc涓枃显然这里需要解码# codinggbkimport codecsprint open(Test.txt).read().decode(utf-8)结果abc中文上面的test.txt我是用Editplus来编辑的但当我用Windows自带的记事本编辑并存成UTF-8格式时运行时报错Traceback (most recent call last):File ChineseTest.py, line 3, inprint open(Test.txt).read().decode(utf-8)UnicodeEncodeError: gbk codec cant encode character u\ufeff in position 0: illegal multibyte sequence原来某些软件如notepad在保存一个以UTF-8编码的文件时会在文件开始的地方插入三个不可见的字符0xEF 0xBB 0xBF即BOM。因此我们在读取时需要自己去掉这些字符python中的codecs module定义了这个常量# codinggbkimport codecsdata open(Test.txt).read()if data[:3] codecs.BOM_UTF8:data data[3:]print data.decode(utf-8)结果abc中文五、文件的编码格式和编码声明的作用源文件的编码格式对字符串的声明有什么作用呢这个问题困扰一直困扰了我好久现在终于有点眉目了文件的编码格式决定了在该源文件中声明的字符串的编码格式例如str 哈哈print repr(str)a.如果文件格式为utf-8则str的值为\xe5\x93\x88\xe5\x93\x88哈哈的utf-8编码b.如果文件格式为gbk则str的值为\xb9\xfe\xb9\xfe哈哈的gbk编码在第一节已经说过python中的字符串只是一个字节数组所以当把a情况的str输出到gbk编码的控制台时就将显示为乱码鍝堝搱而当把b情况下的str输出utf-8编码的控制台时也将显示乱码的问题是什么也没有也许\xb9\xfe\xb9\xfe用utf-8解码显示就是空白吧。_说完文件格式现在来谈谈编码声明的作用吧每个文件在最上面的地方都会用# codinggbk 类似的语句声明一下编码但是这个声明到底有什么用呢到止前为止我觉得它的作用也就是三个声明源文件中将出现非ascii编码通常也就是中文在高级的IDE中IDE会将你的文件格式保存成你指定编码格式。决定源码中类似于u哈这类声明的将‘哈解码成unicode所用的编码格式也是一个比较容易让人迷惑的地方看示例#coding:gbkss u哈哈print repr(ss)print ss:%s % ss将这个些代码保存成一个utf-8文本运行你认为会输出什么呢大家第一感觉肯定输出的肯定是u\u54c8\u54c8ss:哈哈但是实际上输出是u\u935d\u581d\u6431ss:鍝堝搱为什么会这样这时候就是编码声明在作怪了在运行ss u哈哈的时候整个过程可以分为以下几步1) 获取哈哈的编码由文件编码格式确定为\xe5\x93\x88\xe5\x93\x88哈哈的utf-8编码形式2) 转成 unicode编码的时候在这个转换的过程中对于\xe5\x93\x88\xe5\x93\x88的解码不是用utf-8解码而是用声明编码处指定的编码GBK将\xe5\x93\x88\xe5\x93\x88按GBK解码得到就是鍝堝搱这三个字的unicode编码就是u\u935d\u581d\u6431至止可以解释为什么print repr(ss)输出的是u\u935d\u581d\u6431 了。好了这里有点绕我们来分析下一个示例#-*- coding:utf-8 -*-ss u哈哈print repr(ss)print ss:%s % ss将这个示例这次保存成GBK编码形式运行结果竟然是UnicodeDecodeError: utf8 codec cant decode byte 0xb9 in position 0: unexpected code byte这里为什么会有utf8解码错误呢想想上个示例也明白了转换第一步因为文件编码是GBK得到的是哈哈编码是GBK的编码\xb9\xfe\xb9\xfe当进行第二步转换成 unicode的时候会用UTF8对\xb9\xfe\xb9\xfe进行解码而大家查utf-8的编码表会发现utf8编码表关于UTF- 8解释可参见字符编码笔记ASCII、UTF-8、UNICODE中根本不存在所以会报上述错误。

更多文章