Python电子表格式公式解析器?

时间:2012-02-24 19:39:14

标签: python excel parsing spreadsheet formula

我有一个词典列表,例如:

l =[{country:'Italy',sales:100,cost:50}{country:'Italy',sales:130,cost:60}      
    {country:'Germany',sales:110,cost:50}]

我想要一个python函数,它采用类似电子表格的输入字符串(请在下面的@lott中阅读评论)公式如下:

margin = (sales-cost)/sales

它让我回来了:

l = [{country:'Italy',sales:100,cost:50,margin:1} ...]

您知道有任何现有的库吗?或者你知道如何实现它吗?

我已经有了一个想法,如下所示,但我希望有一种更好的方法来解析公式。处理'()'等中的块的东西。

parsed_op = {'sales':1,'cost':-1}
calc_field_name = 'smi'
counter = -1
for d in data:
    counter = counter + 1
    calc = sum([float(d[item])*parsed_op[item] for item in parsed_op])
    d[calc_field_name] = calc
    del data[counter]
    data.append(d)

2 个答案:

答案 0 :(得分:1)

做这样的事情,你会更快乐。

Metrics = namedtuple('Metrics', 'country,sales,cost' )

Margin = namedtuple( 'Margin', 'country,sales,cost,margin' )

metrics = ( Metrics(**row) for row in l ) # a one-use only generator; not a sequence
margin = [ 
    Margin( m.country, m.sales, m.cost,
       margin= (m.sales-m.cost)/m.sales 
    )
for m in metrics ]

这很有效,因为您的公式margin= (m.sales-m.cost)/m.sales非常,非常容易阅读,理解和修改。

答案 1 :(得分:1)

在我看来,真正的问题是将数字放在有文字的地方。

一种方法可以使用re.sub()和一些字典格式(我真的不知道它们的真实姓名,bute here有一些例子)

代码:

import re

dct = {'country': 'Italy', 'sales': 100, 'cost': 50}
formula = 'margin = (sales-cost)/sales'

res_name,operation = formula.split('=')
num_formula = re.sub(r'([a-zA-Z]+)', r'{d[\1]}', operation.strip()).format(d=dct)
num_formula  # '(100-50)/100'

dct[res_name.strip()] = eval(num_formula.format(d=dct))

结果:

{'country': 'Italy', 'cost': 50, 'margin': 0.5, 'sales': 100}

我使用eval()来评估字符串中的数值运算。通常使用eval()是一种不好的做法,但这里非常方便。

无论如何,我确信你可以用其他东西替换eval()评估。


快速解释

re.sub()做了什么:

>>> re.sub(r'([a-zA-Z]+)', r'{d[\1]}', '(sales-cost)/sales')
'({d[sales]}-{d[cost]})/{d[sales]}'
  • r'([a-zA-Z]+)'是模式。
    • [a-zA-Z]匹配任何字母字符。
    • +后面的r'{d[\1]}'告诉匹配一个或多个,在我们的案例中是字母字符,toghter。
    • 括号用于分组。意味着里面的内容将成为一个群体。因为我们只有一对括号将成为第1组。
  • \1是替代品。
    • {d[代表“放在第1组”。
    • 所以基本上要包装与]} >>> '{d[first]} + {d[second]}'.format(d=dct) '1 + 2' 匹配的内容。

要了解有关re模块的更多信息,请查看official doc

格式如何运作:

{{1}}

将这两件事放在一边strip(),这里和那里有干净的字符串,你最终会得到上面的代码。