繁体   English   中英

使用 python xlrd 从 Excel 单元格获取公式

[英]Get formula from Excel cell with python xlrd

我必须将算法从 Excel 工作表移植到 python 代码,但我必须从 Excel 文件对算法进行逆向工程

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 对象中获取公式。 文档中,他们说可以获取公式的字符串版本(使用英语,因为 Excel 文件中没有存储有关函数名称转换的信息)。 他们谈论NameOperand类中的公式(表达式),无论如何我无法理解如何通过必须包含它们的Cell类实例来获取这些类的实例。

你能建议一个从单元格中获取公式文本的代码片段吗?

[Dis]claimer:我是xlrd的作者/维护者。

对公式文本的文档参考是关于“名称”公式的; 阅读文档开头附近的“命名引用、常量、公式和宏”部分。 这些公式在工作表范围或书范围内与名称相关联; 它们与单个细胞无关。 示例: PI映射到=22/7SALES映射到=Mktng!$A$2:$Z$99 编写名称公式反编译器是为了支持检查定义名称的更简单和/或常见用法。

公式通常有几种类型:单元格、共享和数组(都与单元格直接或间接关联)、名称、数据验证和条件格式。

将通用公式从字节码反编译为文本是一项“正在进行的工作”,很慢。 请注意,假设它可用,则您需要解析文本公式以提取单元格引用。 正确解析 Excel 公式并非易事; 与 HTML 一样,使用正则表达式看起来很容易,但行不通。 直接从公式字节码中提取引用会更好。

另请注意,基于单元格的公式可以引用名称,名称公式可以引用单元格和其他名称。 因此,有必要从基于单元格的公式和名称公式中提取单元格和名称引用。 获取有关可用共享公式的信息可能对您有用; 否则解析以下内容:

B2 =A2
B3 =A3+B2
B4 =A4+B3
B5 =A5+B4
...
B60 =A60+B59

您需要自己推断B3:B60公式之间的相似性。

在任何情况下,上述任何一项都不太可能很快可用xlrd优先级在别处。

更新:我已经实现了一个小库来完全按照您的描述执行:从 Excel 电子表格中提取单元格和依赖项并将它们转换为 python 代码。 代码在 github 上,欢迎补丁:)


只是补充一点,您始终可以使用win32com与 excel 进行交互(速度不是很快,但它有效)。 这确实允许您获得公式。 教程可以在这里找到 [缓存副本]和详细信息可以找到 在这一章 [缓存副本]

基本上你只需要:

app.ActiveWorkbook.ActiveSheet.Cells(r,c).Formula

至于建立一个单元格依赖表,一个棘手的事情是解析 excel 表达式。 如果我没记错的话,您提到的跟踪代码并不总是正确执行此操作。 我见过的最好的是EW Bachtal 的算法,其中有一个 Python 实现,效果很好。

所以我知道这是一篇很老的帖子,但我找到了一种从工作簿中的所有工作表中获取公式以及让新创建的工作簿保留所有格式的好方法。

第一步是将 .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 做你想做的事。 您可以查看这篇文章,详细说明为什么实现您需要的功能如此困难。

请注意,开发团队在 python-excel google group 的支持方面做得很好。

耶! 使用 win32com,它对我有用。

import    win32com.client
Excel = win32com.client.Dispatch("Excel.Application")

# python -m pip install pywin32
file=r'path Excel file'
wb = Excel.Workbooks.Open(file)
sheet = wb.ActiveSheet

#Get value
val = sheet.Cells(1,1).value
# Get Formula
sheet.Cells(6,2).Formula

我知道这篇文章有点晚了,但这里没有提到一个建议。 剪切工作表中的所有条目并使用特殊粘贴 (OpenOffice) 进行粘贴。 这会将公式转换为数字,因此不需要额外的编程,这是小型工作簿的合理解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM