Unicode到UTF8的CSV文件 - 通过xlrd的Python

问题描述:

我想使用Python xlrd和csv模块将Excel电子表格转换为CSV,但我在编码问题上挂了。 Xlrd以Unicode生成Excel输出,CSV模块需要UTF-8。Unicode到UTF8的CSV文件 - 通过xlrd的Python

我认为这与xlrd模块无关:一切正常工作输出到标准输出或其他不需要特定编码的输出。

工作表被编码成UTF-16-LE,根据book.encoding

的简化版本的我在做什么是:

from xlrd import * 
import csv 
b = open_workbook('file.xls') 
s = b.sheet_by_name('Export') 
bc = open('file.csv','w') 
bcw = csv.writer(bc,csv.excel,b.encoding) 
for row in range(s.nrows): 
    this_row = [] 
    for col in range(s.ncols): 
     this_row.append(s.cell_value(row,col)) 
    bcw.writerow(this_row) 

这将产生以下错误,在大约740行:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128) 

值是似乎越来越挂在是“516-777316” - 在原来的Excel工作表的文本是“516-7773167”(具有7上的端部)

我会是第一个承认,我只有字符编码是如何工作的一个模糊的感觉,所以大部分是我到目前为止已经试过是.encode.decodes.cell_value(row,col)

各种摸索排列如果有人能够提出解决方案,我将不胜感激 - 如果您能够提供解释什么不起作用以及为什么,以便我可以在未来自己更轻松地调试这些问题,那么更好。

在此先感谢!

编辑:

感谢迄今为止的意见。

当我用户this_row.append(s.cell(row,col))(例如s.cell而不是s.cell_value)整个文档写入没有错误。

输出不是特别理想(text:u'516-7773167'),但它避免了错误,即使有问题的字符仍在输出中。

这让我觉得挑战毕竟可能是xlrd。

想法?

+0

查看整个回溯以了解谁在抛出错误将是有用的。 – Christopher 2009-07-27 16:33:23

+0

没有更多的看到: 文件“the_script。python“,第40行,在 this_row.append(str(s.cell_value(row,col))) UnicodeEncodeError:'ascii'编解码器无法编码字符u'\ xed'在位置5:序号不在范围内(128) – anschauung 2009-07-27 17:37:27

+0

以“从Excel以Unicode输出”,你似乎意味着“UTF-16中从Excel输出”。Unicode定义一个码域,它是由不同的编码系统表示,像UTF-8或UTF-16。 。 – Svante 2009-07-27 17:54:34

我预计cell_value返回值是传给你的问题的Unicode字符串(请打印其type()确认),在这种情况下,你应该能够通过更改此行来解决这个问题:

this_row.append(s.cell_value(row,col)) 

到:

this_row.append(s.cell_value(row,col).encode('utf8')) 

如果cell_value被返回多个不同的类型,那么你需要当且仅当它返回一个Unicode字符串编码;所以你会将这条线分成几行:

val = s.cell_value(row, col) 
if isinstance(val, unicode): 
    val = val.encode('utf8') 
this_row.append(val) 

似乎有两种可能性。一个是你可能没有正确打开输出文件:

“如果csvfile是一个文件对象,它必须在平台上打开并带有'b'标志,这会产生变化。” (http://docs.python.org/library/csv.html#module-csv

如果这不是问题,那么对你的另一个选择是使用codecs.EncodedFile(文件,输入[输出[,错误]])作为一个包装输出您的.csv:

http://docs.python.org/library/codecs.html#module-codecs

这将允许您将传入的UTF16中的文件对象过滤为UTF8。虽然它们在技术上都是“unicode”,但它们编码的方式却非常不同。

事情是这样的:

rbc = open('file.csv','w') 
bc = codecs.EncodedFile(rbc, "UTF16", "UTF8") 
bcw = csv.writer(bc,csv.excel) 

可以解决这个问题对你来说,假设我理解这个问题的权利,并假设写入文件时引发错误。

看起来像你有2个问题。

这个单元格里有东西搞砸了 - '7'应该编码为u'x37'我想,因为它在ASCII范围内。

更重要的是,您收到的错误消息指定ascii编解码器无法使用,这表明您的编码转换为unicode时出现了问题 - 它认为您正在尝试编码值为0xed的值用ASCII代表,但你说你想用unicode代表它。

我没有足够的智慧来确定问题的具体哪一行 - 如果你编辑你的问题来告诉我哪一行导致这个错误信息,我可能会多一点帮助(我想这可能是this_row.append(s.cell_value(row,col))bcw.writerow(this_row),但会感谢您确认)。

你问了解释,但是一些现象在没有你的帮助下是莫名其妙的。 (A)如果可能的话,以UTF16LE编码为由Latin 97创建的Excel中的XLS文件中的字符串。每个字符串携带一个标志,告诉哪个被使用。 Excelier根据用户的“代码页”编码字符串。无论如何,xlrd会产生unicode对象。只有当XLS文件由第三方软件创建时,文件编码才是有意义的,第三方软件可以省略代码页或者说谎言。查看xlrd文档前面的Unicode部分。

(B)原因不明的现象:

此代码:

bcw = csv.writer(bc,csv.excel,b.encoding) 

导致以下错误与Python 2.5,2.6和3.1:TypeError: expected at most 2 arguments, got 3 - 这是关于什么的,我期望给出的文档在csv.writer上;它期望一个类似文件的对象,然后是(1)无(2)方言或(3)一个或多个格式化参数。你给了它一个方言,并且csv.writer没有编码参数,所以splat。你使用的是什么版本的Python?还是你没有复制/粘贴你实际运行的脚本?

(C)周围追溯无法解释的现象,什么实际问题的数据是:

"the_script.py", line 40, in <module> 
this_row.append(str(s.cell_value(row,col))) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128) 

首先,有一个STR()在有问题的代码行,这不是在简单的脚本 - 你不要复制/粘贴您实际运行的脚本?在任何情况下,你都不应该使用str - 你不会在你的浮动上获得完整的精度;只需让csv模块将它们转换即可。

第二,你说“”“价值似乎越来越挂上是”516-777316“ - 原始Excel工作表中的文本是”516-7773167“(结尾是7) “”“ - 很难想象7号如何失败。我会用这样的事情,找出问题的数据,正是:

try: 
    str_value = str(s.cell_value(row, col)) 
except: 
    print "row=%d col=%d cell_value=%r" % (row, col, s.cell_value(row, col)) 
    raise 

也就是说%R打字cell_value=%s ... repr(s.cell_value(row, col))为您节省...的再版()产生的数据提供了明确的表示。学习它。用它。

你是如何在 “516-777316” 到来?

第三,错误消息实际上抱怨一个unicode字符U在“\固定的”偏移量5(即第6个字符)。 U + 00ED是拉丁小写字母I,带有ACUTE,并且在“516-7773167”

中完全没有这样的东西。第四,错误位置似乎是一个移动的目标 - 您在评论其中一个解决方案:“错误在bcw.writerow上。”咦? (D)为什么你得到了这个错误信息(用str()):str(a_unicode_object)试图将unicode对象转换为str对象,并且在没有任何编码信息的情况下使用ascii,但是你有非ASCII数据,所以啪。请注意,您的目标是生成一个用utf8编码的csv文件,但您的简化脚本不会在任何地方提及utf8。 (E)“”“... s.cell(row,col))(egscell而不是s.cell_value)整个文档写入没有错误。输出不是特别理想的(文本:u'516-7773167 “)‘’”

这是怎么回事,因为CSV作家呼唤你的Cell对象的__str__方法,并且这产生<type>:<repr(value)>这可能对调试有用的,但就像你说的不是在你的csv文件如此之大。

(F)亚历克斯·马尔泰利的解决方案是伟大的,因为它得到了你要去然而,你应该阅读Cell类的部分在xlrd文档:类型的细胞是文字,数字,布尔值,日期错误,空白和空当。哟u有日期,你会想要将它们格式化为日期而不是数字,所以你不能使用isinstance()(你可能不希望在函数调用的开销反正)...这是什么Cell.ctype属性和Sheet.cell_type()Sheet.row_types()方法是。

(G)UTF8不是Unicode。 UTF16LE不是Unicode。 UTF16不是Unicode ...以及单个字符串在UTF16 BOM上浪费2个字节的想法对于甚至MS来说都是荒谬的:-)

(H)进一步阅读(除了xlrd文档):

http://www.joelonsoftware.com/articles/Unicode.html 
http://www.amk.ca/python/howto/unicode