4

我收到一个我无法影响其内容的 Excel 文件。它包含一些 Unicode 字符,例如“á”或“é”。

我的代码没有改变,但是我一起从 Eclipse Juno 迁移到 LiClipse 以迁移到不同的 python 包(从 2.5 到 2.6)。原则上,我使用的特定包在 win32com 包上有一个工作版本。

当我阅读 Excel 文件时,我的代码在使用 str() 提取并转换为字符串时崩溃。控制台输出如下:

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

更具体地说,我执行以下操作:

阅读 Excel:

  xlApp = Dispatch("Excel.Application")

  excel = xlApp.Workbooks.Open(excel_location)

在内部循环中,我提取单元格的值:

cell_value = self.excel.ActiveSheet.Cells(excel_line + 1, excel_column + 1)

最后,如果我尝试将 cell_value 转换为 str,则会崩溃:

print str(cell_value)

如果我去 Excel 并删除非 ASCII 字符,一切都会顺利进行。我已经尝试过这个编码提案。我用谷歌搜索的任何其他解决方案都建议以特定格式保存文件,这是我做不到的。

令我困惑的是,代码之前使用相同的输入 Excel 工作,但对 LiClipse 和 2.6 Python 的这种更改杀死了一切。

知道我该如何进步吗?

4

4 回答 4

3

这是在 Python 2.x 中处理 UTF-8 编码的 Unicode 数据时的常见问题。在 2.4 和 2.7 之间的一些地方对此的处理已经改变,所以你突然得到一个错误也就不足为奇了。

错误的来源是print:在 Python 2.x 中,print不会尝试假设您的终端支持什么编码。它只是播放保存并假定这ascii是唯一受支持的字符集(这意味着 0 到 127 之间的字符很好,其他一切都会出错)。

现在您将 a 转换COMObject为字符串。str就 Python 2.x 而言,它只是一堆字节(值 0 到 255)。它没有编码。

将两者结合起来会带来麻烦。当 Python 打印时,它会尝试验证输入(字符串)并突然发现 UTF-8 编码字符(UTF-8 添加了这些奇怪\xe1的标记,告诉解码器下一个字节在某种程度上是特殊的;查看 Wikipedia 以获取血腥细节)。

那时ascii编码器会说:对不起,帮不了你。

这意味着你可以使用这个值,比较它等等,但你不能print。打印问题的简单解决方法是:

s = str(cell_value) # Convert COM -> UTF-8 encoded string
print repr(s) # repr() converts anything to ascii

如果你的终端支持 UTF-8,那么你需要告诉 Python:

import sys
import codecs

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

您还应该看看sys.stdout.encoding哪个告诉 Python 当前认为输出编码是/应该是什么。当 Python 2 被正确配置时(比如在现代 Linux 发行版上),那么应该自动使用正确的输出编解码器。

有关的:

于 2015-04-21T11:51:15.837 回答
2

此处描述的是一种 hack,您不应将其用作长期解决方案。查看评论可能会破坏终端。

最后,我在@Huan-YuTseng 提供的建议的帮助下找到了一个解决方案,可能其他人提供的解决方案可能适用于其他环境,但不适用于这个环境。

所以,发生的事情是我从 Eclipse Juno 版本(因为 Pydev 由于需要我无法在这台计算机上完成的 Java 升级而停止工作)迁移到 LiClipse 直接包(我没有升级下载的 Eclipse 版本)。

默认情况下,在我的 LiClipse 版本 (1.4.0.201502042042) 中,控制台输出默认不是 utf-8。所以我需要更改 LiClipse 的输出或使用我的代码。幸运的是,还有另一个与类似问题相关的问题对我有所帮助。您可以在此处查看更多详细信息,但本质上您需要做的是在代码的开头包含以下代码:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

一切正常。在@AarongDigulla 的答案中,解决方案就在那里,但实际上是最后一个解决方案。

但是,我需要说 LiClipse 在 sys.setdefaultencoding 语句上给了我一个错误,在执行过程中不会产生任何问题......不知道发生了什么。这阻止了我之前测试这个解决方案。也许 LiClipse 有问题(让我执行有错误的代码!)

于 2015-04-22T07:27:31.357 回答
2

.Cells(row,col)返回一个Range对象。您可能想要单元格中的文本:

cell = xl.ActiveSheet.Cells(1,2).Text

或者

cell = xl.ActiveSheet.Range('B1').Text

结果值将是一个 Unicode 字符串。要转换为可以写入文件的字节,请使用.encode(encoding),例如:

bytes = cell.encode('utf8')

以下示例使用以下电子表格:

在此处输入图像描述

import win32com.client
xl = win32com.client.gencache.EnsureDispatch('Excel.Application')
xl.Workbooks.Open(r'book1.xlsx')
cell = xl.ActiveSheet.Cells(1,2)
cell_value = cell.Text
print repr(cell)
print repr(cell_value)
print cell_value

输出(注意,只有控制台/IDE支持字符时才会打印中文):

<win32com.gen_py.Microsoft Excel 14.0 Object Library.Range instance at 0x129909424>
u'\u4e2d\u56fd\u4eba'
中国人
于 2015-04-21T15:53:42.187 回答
0

使用'utf-8 BOM',在python中用作Unicode字符的utf_8_sig,也可以避免Excel工作表中的不相关结果。

于 2019-06-12T11:19:47.157 回答