从Excel单元格与python xlrd获取公式
我必须将algorithm从Excel工作表移植到Python代码,但是我必须从Excel文件中反向devisealgorithm 。
Excel工作表非常复杂,它包含许多单元格,其中有公式引用其他单元格(也可以包含公式或常量)。
我的想法是用python脚本分析单元格之间的依赖关系表,即:
A1取决于B4,C5,E7公式:“= sqrt(B4)+ C5 * E7”
A2取决于B5,C6公式:“= sin(B5)* C6”
…
xlrd python模块允许读取XLS工作簿,但目前我可以访问单元格的值 ,而不是公式 。
例如,用下面的代码,我可以简单地得到一个单元格的值:
import xlrd #open the .xls file xlsname="test.xls" book = xlrd.open_workbook(xlsname) #build a dictionary of the names->sheets of the book sd={} for s in book.sheets(): sd[s.name]=s #obtain Sheet "Foglio 1" from sheet names dictionary sheet=sd["Foglio 1"] #print value of the cell J141 print sheet.cell(142,9)
无论如何,它似乎没有办法从.cell(…)方法返回的Cell对象的formul 。 在文档中,他们说可以获得公式的string版本(英文是因为没有关于函数名称转换的信息存储在Excel文件中)。 他们在名称和操作数类中谈论公式(expression式),无论如何我不明白如何通过必须包含它们的Cell类实例来获取这些类的实例。
你能build议一个代码片段,从单元格获取公式文本?
[Dis] claimer:我是xlrd
的作者/维护者。
公式文本的文档引用是关于“名称”公式; 阅读文档开头附近的“命名引用,常量,公式和macros”部分。 这些公式与表名或书名相关联; 它们不与个体细胞相关联。 示例: PI
映射到=22/7
=Mktng!$A$2:$Z$99
, SALES
映射到=Mktng!$A$2:$Z$99
。 编写名称反编译器是为了支持检查定义名称的更简单和/或常见的用法。
公式一般有几种:单元格,共享和数组(全部与单元格直接或间接相关),名称,数据validation和条件格式。
从字节码到文本的反编译是一个“正在进行中”的过程。 请注意,假设它可用,则需要parsing文本公式以提取单元格引用。 正确parsingExcel公式并非易事。 与HTML一样,使用正则expression式看起来很简单,但不起作用。 直接从公式字节码中提取引用会更好。
另请注意,基于单元格的公式可以引用名称,名称公式可以引用单元格和其他名称。 所以有必要从基于单元格和名称公式中提取单元格和名称引用。 获得有关共享公式的信息可能对您有用; 否则parsing以下内容:
B2 =A2 B3 =A3+B2 B4 =A4+B3 B5 =A5+B4 ... B60 =A60+B59
您需要自行推断B3:B60
公式之间的相似性。
在任何情况下,上述任何一种情况都不会很快出现 – xlrd
优先考虑事项。
更新 :我已经走了,并实现了一个小库来完成你所描述的:从Excel电子表格中提取单元格和依赖关系,并将它们转换为Python代码。 代码在github上 ,补丁欢迎:)
只要添加一下,你总是可以使用win32com与excel进行交互 (不是很快,但它的工作原理)。 这确实可以让你得到公式。 教程可以在这里find ,细节可以find 在本章中 [caching副本] 。
基本上你只是做:
app.ActiveWorkbook.ActiveSheet.Cells(r,c).Formula
至于build立一个单元格依赖关系表,棘手的是parsingexcelexpression式。 如果我没有记错,你提到的跟踪代码并不总是这样做。 我见过的最好的是EW Bachtal的algorithm ,其中一个python实现可用,效果很好。
所以我知道这是一个非常古老的post,但是我发现从工作簿中的所有工作表中获取公式的一种体面的方式,以及使新创build的工作簿保留所有的格式。
第一步是将.xlsx文件的副本保存为.xls – 在下面的代码中使用.xls作为文件名
使用Python 2.7
from lxml import etree from StringIO import StringIO import xlsxwriter import subprocess from xlrd import open_workbook from xlutils.copy import copy from xlsxwriter.utility import xl_cell_to_rowcol import os file_name = '<YOUR-FILE-HERE>' dir_path = os.path.dirname(os.path.realpath(file_name)) subprocess.call(["unzip",str(file_name+"x"),"-d","file_xml"]) xml_sheet_names = dict() with open_workbook(file_name,formatting_info=True) as rb: wb = copy(rb) workbook_names_list = rb.sheet_names() for i,name in enumerate(workbook_names_list): xml_sheet_names[name] = "sheet"+str(i+1) sheet_formulas = dict() for i, k in enumerate(workbook_names_list): xmlFile = os.path.join(dir_path,"file_xml/xl/worksheets/{}.xml".format(xml_sheet_names[k])) with open(xmlFile) as f: xml = f.read() tree = etree.parse(StringIO(xml)) context = etree.iterparse(StringIO(xml)) sheet_formulas[k] = dict() for _, elem in context: if elem.tag.split("}")[1]=='f': cell_key = elem.getparent().get(key="r") cell_formula = elem.text sheet_formulas[k][cell_key] = str("="+cell_formula) sheet_formulas
字典结构'sheet_formulas'
{'Worksheet_Name': {'A1_cell_reference':'cell_formula'}}
示例结果:
{u'CY16': {'A1': '=Data!B5', 'B1': '=Data!B1', 'B10': '=IFERROR(Data!B12,"")', 'B11': '=IFERROR(SUM(B9:B10),"")',
现在看来,现在不可能用xlrd来做你想做的事情。 你可以看看这篇文章 ,详细描述为什么要实现你所需要的function是非常困难的。
请注意,开发团队在python-excel谷歌组中的支持方面做得非常出色。
我知道这个post有点晚,但有一个build议,这里没有被覆盖。 从工作表中剪切所有条目,并使用粘贴特殊(OpenOffice)进行粘贴。 这将公式转换为数字,所以不需要额外的编程,这是小工作簿的合理解决scheme。