在python中正确解码unicode的麻烦

时间:2013-07-09 17:11:54

标签: python excel unicode xlrd xlwt

我有一个使用xlwt / xlrd处理excel文件的python脚本。在我的脚本开头,我有以下代码:

#if you got a csv in parameters, convert it to an xls file
if '.csv' in sys.argv[1]:
    #name of new file after conversion is finished
    name = sys.argv[1]
    csvfile = open(sys.argv[1], 'rb')
    try:
        #extract data from .csv
        csvReader = csv.reader(csvfile, delimiter=' ', quotechar='|')
        csvData = list(csv.reader(open(name, 'rb')))
        # write to a xls file
        outFile = xlwt.Wrokbook()
        newSheet = outFile.add_sheet('Sheet 1')
        # traverse over 2d array to write each individual cell
        for row in range(len(csvData)):
            for col in range(len(csvData[0])):
                newSheet.write(row, col, csvData[row][col].encode('utf8'))
         name = name[:-4] + ".xls" #change extension of file
         outFile.save(name)
         wb = open_workbook(name)
    finally:
         csvfile.close()

哪个给出了错误

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 44: ordinal not in range(128)

在行outFile.save(名称)

到目前为止我发现的唯一有用的东西是UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 1,但我的终端使用utf8作为其编码。

编辑: 完全忘了提这个,很抱歉。

我认为带.encode的行会以某种方式导致错误,但我无法思考如何。我最初没有.encode,然后我添加.encode('utf8'),也尝试.encode('utf-8')和unicode(字符串,'utf8')。我不确定还有什么可以解决这个问题。

编辑: 我试过Brian的建议无济于事。另外,我尝试了codecs.open建议,并尝试在创建工作簿时指定编码。这些都不会改变错误。我尝试过的唯一改变错误的是使用newSheet.write在行上添加.encode。没有它,我得到:

UnicodeEncodeError: 'ascii' codec can't encode character u'\u2013' in position 44: ordinal no in range(128)

有了它,我得到了:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 44: ordinal not in range(128)

3 个答案:

答案 0 :(得分:1)

根据docs

  

csv模块不直接支持读写Unicode,   但是对于ASCII NUL的一些问题,它是8位清除   字符。所以你可以编写处理函数的函数或类   只要你避免像编码一样编码和解码   使用NUL的UTF-16。建议使用UTF-8。

尝试使用以下代码段,该代码段为您提供了一个使用unicode数据读取csv的生成器。请注意,此代码直接来自上面链接的文档:

import csv

def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                            dialect=dialect, **kwargs)
    for row in csv_reader:
        # decode UTF-8 back to Unicode, cell by cell:
        yield [unicode(cell, 'utf-8') for cell in row]

def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')

作为如何使用上述代码的示例,而不是

csvReader = csv.reader(csvfile, delimiter=' ', quotechar='|')

使用

csvReader = unicode_csv_reader(csvfile, delimiter=' ', quotechar='|')

yield是生成器函数的返回等价物。该函数返回一个生成器对象,它是python中的一种可迭代类型。 **kwargs表示关键字参数,这是您在编写delimiter=' ', quotechar='|'

时实际传递的内容

答案 1 :(得分:0)

问题是当你的输入中有非ascii字符时,你不会以它期望的状态将它们传递给xlwt。

根据xlwt的文档:

  

unicode实例按原样编写。使用在创建Workbook实例时指定的编码(默认值:'ascii')将str实例转换为unicode。

https://secure.simplistix.co.uk/svn/xlwt/trunk/xlwt/doc/xlwt.html?p=4966#xlwt.Worksheet.write-method

也就是说,当您的输入csv文件包含使用utf-8编码的非ascii字符时,读取器会将其作为编码的Python字符串拉入 - 如果您直接查看它,则会看到多个十六进制字节,例如{ {1}}小写a-acute。当您将其写入工作表时,它必须解码它。在创建工作簿时,您没有指定编码,因此它尝试使用默认的'\xc3\xa1'编码执行此操作。如你所见,这不起作用,因为那些不是ascii字节。

您的选择是将Unicode字符串传递给工作表,从csv阅读器的结果解码它们(或将csv阅读器包装在解码所有内容的东西中 - 它是相同的东西)或者在创建时在工作簿上设置编码它

答案 2 :(得分:0)

尝试使用内置编解码器库打开文件:

#!/usr/bin/env python2.7
# -*- coding: UTF-8 -*-
import codecs

with codecs.open(sys.argv[1], "rb", encoding="utf-8") as csvfile:
    csvReader = csv.reader(csvfile, delimiter=' ', quotechar='|')
    # snipped the rest of the code