Получить формулу из ячейки Excel с помощью Python Xlrd - PullRequest
24 голосов
/ 14 января 2011

Мне нужно перенести алгоритм из листа Excel в код Python , но мне нужно провести обратный инжиниринг алгоритма из файла Excel .

Лист Excel довольно сложный, он содержит много ячеек, в которых есть формулы, ссылающиеся на другие ячейки (которые также могут содержать формулу или константу).

Моя идея состоит в том, чтобы проанализировать с помощью сценария на языке Python лист, формирующий своего рода таблицу зависимостей между ячейками, а именно:

A1 зависит от формулы B4, C5, E7: "= sqrt (B4) + C5 * E7"
A2 зависит от B5, формула C6: "= sin (B5) * C6"
...

Модуль Python xlrd позволяет читать рабочую книгу 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 не хранится информация о переводе имени функции). Они говорят о формулах (выражениях) в классах Name и Operand , так или иначе, я не могу понять, как получить экземпляры этих классов экземпляром класса Cell , который должен содержать их.

Не могли бы вы предложить фрагмент кода, который получает текст формулы из ячейки?

Ответы [ 5 ]

21 голосов
/ 14 января 2011

[Dis] claimer: Я автор / сопровождающий xlrd.

Ссылки в документации на текст формулы относятся к формулам "name"; прочитайте раздел «Именованные ссылки, константы, формулы и макросы» в начале документации. Эти формулы связаны с именем всего листа или всей книги; они не связаны с отдельными клетками. Примеры: PI отображается на =22/7, SALES отображается на =Mktng!$A$2:$Z$99. Декомпилятор формулы имени был написан для поддержки проверки более простого и / или часто встречающегося использования определенных имен.

Формулы в целом бывают нескольких видов: ячейка, общий ресурс и массив (все связаны с ячейкой, прямо или косвенно), имя, проверка данных и условное форматирование.

Медленная декомпиляция общих формул из байт-кода в текст. Обратите внимание, что, предположив, что он доступен, вам нужно будет проанализировать текстовую формулу, чтобы извлечь ссылки на ячейки. Правильный анализ формул Excel - задача не из легких; как и в HTML, использование регулярных выражений выглядит легко, но не работает. Было бы лучше извлечь ссылки непосредственно из байт-кода формулы.

Также обратите внимание, что формулы на основе ячеек могут ссылаться на имена, а формулы имен могут ссылаться как на ячейки, так и на другие имена. Поэтому было бы необходимо извлечь ссылки на ячейки и имена из формул на основе ячеек и имен. Возможно, вам будет полезно иметь информацию об общих формулах; в противном случае проанализировав следующее:

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

вам нужно будет самостоятельно определить сходство формул B3:B60.

В любом случае, ни один из вышеперечисленных, вероятно, не будет доступен в ближайшее время - xlrd приоритеты лежат в другом месте.

12 голосов
/ 29 июня 2011

Обновление : я пошел и реализовал небольшую библиотеку, чтобы делать именно то, что вы описываете: извлечение ячеек и зависимостей из электронной таблицы Excel и преобразование их в код на языке Python.Код на github , исправления приветствуются :)


Просто добавьте, что вы всегда можете взаимодействовать с Excel, используя win32com (не очень быстро, но работает),Это позволяет вам получить формулу.Учебное пособие можно найти здесь , а подробности можно найти в этой главе [кэшированная копия] .

По существувы просто делаете:

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

Что касается построения таблицы зависимостей ячеек, то сложно разобрать выражения Excel.Если я правильно помню код трассировки, который вы упомянули, не всегда делает это правильно.Лучшее, что я видел, это алгоритм EW Bachtal , из которых доступна реализация на python, которая хорошо работает.

5 голосов
/ 13 ноября 2016

Итак, я знаю, что это очень старая запись, но я нашел достойный способ получения формул из всех листов рабочей книги, а также чтобы только что созданная рабочая книга сохранила все форматирование.

СначалаШаг - сохранить копию вашего файла .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),"")',
2 голосов
/ 14 января 2011

Кажется, что теперь невозможно делать то, что вы хотите с xlrd. Вы можете взглянуть на этот пост для подробного описания того, почему так сложно реализовать необходимые функции.

Обратите внимание, что команда разработчиков отлично справляется с поддержкой в ​​группе Google Python-Excel.

0 голосов
/ 27 июля 2013

Я знаю, что этот пост немного запоздал, но есть одно предложение, которое здесь не освещалось. Вырежьте все записи из листа и вставьте, используя специальную вставку (OpenOffice). Это преобразует формулы в числа, поэтому нет необходимости в дополнительном программировании, и это разумное решение для небольших рабочих книг.

...