簡體   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