如何使用Python读取Excel中的Unicode字符

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转换为字符串,会崩溃:

print str(cell_value)

如果我在Excel中删除非ASCII字符,则一切都能顺利进行。 我尝试了这个编码建议。 我查找的任何其他解决方案都建议以特定格式保存文件,但我无法这样做。
令我困惑的是,使用相同的输入Excel时,该代码之前是正常工作的,但转换为LiClipse和2.6 Python后就出现问题了。
有什么想法可以帮助我前进吗?

为什么你在使用str()函数? - Padraic Cunningham
@PadraicCunningham,当我创建我的代码时,我读到的是提出的解决方案。我已经尝试过Unicode,但它没有起作用。您有其他建议吗? - Trebia Project.
1
我的意思是当您使用无字符串调用的print(cell_value)时会发生什么。 - Padraic Cunningham
1
也许这个链接可以帮到你:http://www.ianbicking.org/illusive-setdefaultencoding.html - Huan-Yu Tseng
@Huan-YuTseng 那并没有直接帮助我,但是给了我一个提示,让我找到了解决方案!!!问题似乎出在 LiClipse 中。 - Trebia Project.
显示剩余14条评论
4个回答

3
这是在Python 2.x中使用UTF-8编码Unicode数据时的常见问题。在2.4到2.7之间,处理方式已经发生了一些改变,因此突然出现错误也就不足为奇了。
错误的源头是“print”:在Python 2.x中,“print”不会尝试假设您的终端支持什么编码。它只是安全地假设“ascii”是唯一支持的字符集(这意味着0到127之间的字符是可以的,其他所有字符都会导致错误)。
现在你将一个“COMObject”转换为字符串。“str”在Python 2.x中只是一堆字节(值从0到255)。它没有编码。
将两者结合起来就会带来麻烦。当Python打印时,它会尝试验证输入(字符串),然后突然发现UTF-8编码的字符(UTF-8添加这些奇怪的“\xe1”标记,告诉解码器下一个字节在某种程度上是特殊的;请查看维基百科以获取详细信息)。

这时,ascii编码器会说:抱歉,我无法帮助你。

这意味着您可以使用此值进行比较等操作,但无法进行打印。解决打印问题的简单方法是:

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发行版),则应自动使用正确的编解码器进行输出。

相关:


这些都不起作用。实际上,在宣布这个问题之前,我已经尝试过其中的一些方法。 - Trebia Project.
请观看我提供的“实用 Unicode”演讲,它应该能帮助您理解为什么会出现错误。我还建议您升级到最新的Python 2.7版本。 - Aaron Digulla
我已经阅读了它,其中描述的任何内容都已经在其他地方提供。升级到Python 2.7是一项重大任务... 更像是一种hack而不是解决方案。 - Trebia Project.
实际上,解决方案就是你最后提供的链接,但是当我在LiClipse中引入它时,出现了错误,并且我进行了双重检查并执行了带有错误的代码!为了帮助可能遇到同样问题的读者,我更明确地表述了你的解决方案,但是解决方案是由你提供的!问题已解决! - Trebia Project.

3

.Cells(row,col) 返回一个 Range 对象。你可能需要从单元格中获取文本:

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

或者

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

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

bytes = cell.encode('utf8')

下面的示例使用以下电子表格: enter image description here
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'
中国人

很遗憾,它不起作用。以防万一有人在未来阅读此内容,我在您的解决方案中修改了一个小问题,即cell不允许调用Value方法。 - Trebia Project.
@TrebiaProject,描述“不工作”的原因是我已经测试过了,那是输出的剪切粘贴。正如您所看到的,它返回一个“Range”对象,Microsoft文档支持“Value”属性:https://msdn.microsoft.com/EN-US/library/office/ff838238.aspx - Mark Tolonen
@TrebiaProject,“cell.Text”也是适当的,并在MSDN文档中描述为返回字符串。 "cell.Value"返回一个变量,可能无法在您的旧Python/pywin32安装中正确处理。 我正在使用Python 2.7/pywin32 219。 我更新了我的答案以使用“.Text”。 - Mark Tolonen
我的错误,我应该更明确一些。问题仍然存在,输出完全相同。我发现问题实际上是控制台的问题。 - Trebia Project.

2
这里描述的是一个hack,不应该作为长期解决方案。从评论中可以看出,它可能会破坏终端。
最后,我找到了一种解决方法,得益于@Huan-YuTseng提供的建议,也许其他人提供的解决方案在其他情况下可能有效,但在这种情况下不行。
所以,我的情况是从Eclipse Juno版本迁移到LiClipse直接包(由于需要Java升级而无法在此计算机上完成,因此Pydev停止工作)。
默认情况下,在我的LiClipse版本(1.4.0.201502042042)中,控制台输出不是utf-8。因此,我需要从LiClipse或使用我的代码更改输出。幸运的是,有另一个与类似问题相关的问题帮助了我。您可以在这里查看更多详细信息,但基本上您需要在代码开头包含以下代码:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

一切都正常。在@AarongDigulla的回答中,解决方案已经给出,但实际上是最后一个解决方案。

然而,我需要说的是,LiClipse在sys.setdefaultencoding语句上给了我一个错误,在执行期间没有创建任何问题...不知道发生了什么。这使我无法在测试此解决方案之前停止。也许LiClipse有问题(它允许我执行带有错误的代码!)


еңЁPythonи„ҡжң¬дёӯдёҚеә”иҜҘйңҖиҰҒиҝҷж ·еҒҡгҖӮз”ұдәҺLiClipseжҳҜPyDevзҡ„继жүҝиҖ…пјҢиҝҷжңүеё®еҠ©еҗ—пјҹhttps://dev59.com/questions/fU7Sa4cB1Zd3GeqP3GEp - Aaron Digulla
@AaronDigulla 谢谢,实际上这就是问题的一部分,Eclipse 中有几个选项在 LiClipse 中不可用。例如,无法选择运行配置(这让我感到震惊),LiClipse 和 Eclipse 的默认配置不同。 - Trebia Project.
这会更改所有Python模块的默认设置,不建议这样做。一些模块依赖于此默认设置。 - Mark Tolonen
@TrebiaProject,实际上,在我的答案代码中尝试在IDE中使用reload(sys)技巧使IDE停止工作...这是不更改默认值的好例子。但是,它确实使Range对象可打印,但正确的方法是使用cell.Text来检索Range对象的文本。 - Mark Tolonen
@MarkTolonen,目前它对我有效。到目前为止,我还没有找到确切的LiClipse配置使其工作...仍在调查中,当我找到时,我将为社区提供信息,但短期内我已经解除了阻塞。 - Trebia Project.
@MarkTolonen 我会在答案中明确那个评论,以防有人看到它。 - Trebia Project.

0

在编程中,使用“utf-8 BOM”(在Python中用作utf_8_sig)来处理Unicode字符,并避免在Excel表格中出现不相关的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接