出现这个问题是在ubuntu16.04 python2.7的环境下,我将txt文件转换为xml文件,其中txt文件中有中文,我主要将涉及到中文部分转换的代码贴出来(其余部分就不贴了),便于分析。txt文件的内容如
转换代码如下,其完成的内容是将字符串‘星期一’写入xml文件。
import os
from xml.dom.minidom import Document
import sys
def writeXml(tmp, imgname):
doc = Document()
#owner
annotation = doc.createElement('annotation')
doc.appendChild(annotation)
#owner
folder = doc.createElement('folder')
annotation.appendChild(folder)
folder_txt = doc.createTextNode("VOC2007")
folder.appendChild(folder_txt)
filename = doc.createElement('filename')
filename_txt = doc.createTextNode(imgname[0])
filename.appendChild(filename_txt)
#onee#
with open(tmp, 'wb') as f:
f.write(doc.toprettyxml(indent='\t', encoding='utf-8'))
return
if __name__ == '__main__':
txtpath = '/home/yantianwang/123.txt'
xmlpath = '/home/yantianwang/123.xml'
with open(txtpath, 'r') as f_in: #打开txt文件
lines = f_in.readlines()
content = [x.strip().split(' ') for x in lines] #根据空格分割
writeXml(xmlpath, content[0])
如果运行上述代码会在这一句跳出一个错误。
filename_txt = doc.createTextNode(imgname[0])
错误为:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 0: ordinal not in range(128)
那么为什么会出现这个错误?那么就要搞清楚各个编码格式
上述代码只是将‘星期一’这个中文字符写入xml,也就是image[0] = ‘星期一’,那么它的格式是什么呢?
可以用下面这个代码查看这个字符串的格式:
import chardet
print chardet.detect(imgname[0])
输出为:
{'confidence': 0.87625, 'language': '', 'encoding': 'utf-8'}
也就是有0.876的概率它的格式是utf-8,其实也就是说格式为utf-8。
然后这里我在引用博客中的一段话:
如果上述字符在解释器上输入的,那么这个s的格式就是解释器的编码格式,对于windows的cmd而言,就是gbk。
如果将段代码是保存后才执行的,比如存储为utf-8,那么在解释器载入这段程序的时候,就会将s初始化为utf-8编码。
也就是一般来讲,在python2.7中中文字符是默认初始化为utf-8
此外我也顺路看了一下,字符串‘Sunday’和字符串‘1’的编码格式,两者都为ascii
刚刚搞清楚了字符的编码格式为utf-8,那么系统的默认编码格式呢?可以用一句代码查看:
print (sys.getdefaultencoding())
输出为:ascii。
也就是说如果你在python中进行编码和解码的时候,不指定编码方式,那么python就会使用defaultencoding,即ascii
因此再将字符串写入xml的过程实际上这样的:
imgname[0].decode('ascii')
那么这样错了吗?再往下看
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 可以右下图表示,图中utf-8和gbk都是编码的类型。
编码(encode):将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。
解码(decode):将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。
这时候就应该明白了,系统默认采用的编码和解码的方式是ascii,实际过程是imgname[0].decode('ascii'),而我们imgname[0]的编码格式是utf-8,按照上面讲的解码,正确的解码方式应该为imgname[0].decode('utf-8'),因此才会出现前面的错误。
其实已经说了一个解决方法了,就是将代码改成如下,就是用它编码的方式解码它,而不是用系统默认的ascii的方式。
filename_txt = doc.createTextNode(imgname[0].decode('utf-8'))
有一个一劳永逸的方法,就是在代码的开头直接添加上如下代码,将默认的编码方式改为utf-8就行啦。
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
如果此时你的代码中有print,那么可能加上上述代码之后就print不出来了。那么就改成如下代码就可以了。
import sys
stdi, stdo, stde = sys.stdin, sys.stdout, sys.stderr
reload(sys)
sys.setdefaultencoding('utf-8')
sys.stdin, sys.stdout, sys.stderr = stdi, stdo, stde