我正在尝试使用 Python xlrd 和 csv 模块将 Excel 电子表格转换为 CSV,但我遇到了编码问题。Xlrd 以 Unicode 格式从 Excel 生成输出,而 CSV 模块需要 UTF-8。

我想这与 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 中。

想法?

有帮助吗?

解决方案

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

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)

其他提示

你要求解释,但如果没有你的帮助,有些现象是无法解释的。

(A) 如果可能,Excel 97 及以上版本创建的 XLS 文件中的字符串将以 Latin1 编码,否则以 UTF16LE 编码。每个字符串都带有一个标志,表明使用了哪个字符串。早期的 Excel 根据用户的“代码页”对字符串进行编码。任何状况之下, 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)) ...repr() 生成数据的明确表示。学习它。用它。

您是如何到达“516-777316”的?

第三,错误消息实际上是在抱怨偏移量 5 处的 unicode 字符 u'\xed' (即第六个字符)。U+00ED 是带锐音的拉丁文小写字母 I,而“516-7773167”中根本没有类似的内容

第四,错误位置似乎是一个移动目标——您在对其中一个解决方案的评论中说:“错误是在BCW.Writerow上。”嗯?

(D) 为什么您收到该错误消息(使用 str()): str(a_unicode_object) 尝试将 unicode 对象转换为 str 对象,并且在没有任何编码信息的情况下使用 ascii,但您有非 ascii 数据,因此 splat.请注意,您的目标是生成一个以 utf8 编码的 csv 文件,但您的简化脚本在任何地方都没有提到 utf8。

(E) “””...s.cell(row,col)) (例如s.cell 代替 s.cell_value) 整个文档写入没有错误。输出不是特别理想(文本:u'516-7773167')"""

发生这种情况是因为 csv 作者正在调用 __str__ 你的 Cell 对象的方法,这会产生 <type>:<repr(value)> 这可能对调试很有用,但正如你所说,在你的 csv 文件中不太好。

(F) Alex Martelli 的解决方案很棒,因为它让您继续前进。但是,您应该阅读 xlrd 文档中有关 Cell 类的部分:单元格的类型有文本、数字、布尔值、日期、错误、空白和空。如果您有日期,您将希望将它们格式化为日期而不是数字,因此您不能使用 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

看起来你已经有了2个问题。

有什么东西在该小区一团糟 - “7”应当被编码为u'x37' 我想,因为它是ASCII范围内

更重要的是,你得到一个错误信息指定的编解码器ascii不能使用的这个事实,有什么地方错了你的编码转换成Unicode - 它认为你想编码值0xed可以”吨ASCII表示,但你说你要代表它以Unicode。

我不够聪明,制定出具体的路线是什么导致了问题 - 如果您编辑您的问题告诉我什么行的引起我也许能帮助更多一点的错误信息(我猜它要么this_row.append(s.cell_value(row,col))bcw.writerow(this_row),但希望你确认)。

有出现两个可能性。其中之一是,你还没有打开也许正确的输出文件:

“如果csvfile是一个文件对象,必须将其与平台上的‘b’标记,其中有差别打开。” ( http://docs.python.org/library/csv.html#module -csv

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

http://docs.python.org/library/codecs.html #模块的编解码器

这将允许你有来自进入到UTF16 UTF8文件对象的过滤器。虽然两者在技术上是“统一”,它们编码的方式有很大的不同。

像这样:

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top