ubuntu下出现UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 48: ordinal not in ran

问题描述

出现这个问题是在ubuntu16.04 python2.7的环境下,我将txt文件转换为xml文件,其中txt文件中有中文,我主要将涉及到中文部分转换的代码贴出来(其余部分就不贴了),便于分析。txt文件的内容如

ubuntu下出现UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 48: ordinal not in ran_第1张图片

转换代码如下,其完成的内容是将字符串‘星期一’写入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)

 那么为什么会出现这个错误?那么就要搞清楚各个编码格式

 

str与字节码 

上述代码只是将‘星期一’这个中文字符写入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都是编码的类型。

ubuntu下出现UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 48: ordinal not in ran_第2张图片

编码(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'),因此才会出现前面的错误。

 

解决方法1

其实已经说了一个解决方法了,就是将代码改成如下,就是用它编码的方式解码它,而不是用系统默认的ascii的方式。

filename_txt = doc.createTextNode(imgname[0].decode('utf-8'))

解决方法2

有一个一劳永逸的方法,就是在代码的开头直接添加上如下代码,将默认的编码方式改为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

 

 

你可能感兴趣的:(python,编码解码)