Python - 在字符串中评估数学表达式

时间:2012-08-28 16:03:26

标签: python string math expression eval

我有一个关于在字符串中评估数学表达式的问题。 例如,我的字符串如下:

my_str='I have 6 * (2 + 3) apples'

我想知道如何评估此字符串并获得以下结果:

'I have 30 apples'

有没有办法做到这一点?

提前致谢。

P.S。在这种情况下,python的eval函数没有帮助。在尝试使用eval函数进行评估时,它引发了错误。

8 个答案:

答案 0 :(得分:2)

这是我的尝试:

>>> import string
>>> s = 'I have 6 * (2+3) apples'
>>> symbols = '^*()/+-'
>>> formula = [(x,s.index(x)) for x in s if x in string.digits+symbols]
>>> result = eval(''.join(x[0] for x in formula), {'__builtins__':None})
>>> s = s[:formula[0][1]] + str(result) + s[formula[-1][1]+1:]
>>> s
'I have 30 apples'

注意:

这很简单,它不会处理复杂的方程式 - 比如平方根,pi等等,但我相信它的问题在于它的精神。对于真正的健壮的答案,请参阅question posted by jeffery_the_wind;但我认为这种简单化的案例可能有点过头了。

答案 1 :(得分:2)

有时候,简化问题而不是提出复杂的解决方案会更好。您可能希望通过像这样提供代码来简化问题

my_str='I have {6 * (2 + 3)} apples'

这样你就可以使用一个简单的正则表达式解析它并评估里面的内容。否则你会有很多复杂性。

答案 2 :(得分:1)

这是一个非常棘手的问题,一般来说几乎不可能解决。但是,这是一个简单的方法来解决与示例输入一起使用的问题。

*步骤1 - 清理输入。这是一般来说最困难的部分。基本上,你需要一种方法从字符串中提取单个数学表达式而不会破坏它。这里有一个简单的正则表达式:

sanitized = re.sub(r'[a-zA-Z]','',my_str).strip()

*第2步 - 使用eval进行评估:

value = eval(sanitized, {'__builtins__':None})

*第3步 - 替代

new_string = my_str.replace(sanitized, str(value))

答案 3 :(得分:1)

感谢大家的帮助。实际上,我提供的示例与我在实际任务中所拥有的相比非常简单。我从文件中读取这些字符串,有时候可以有这样的视图:

my_str='ENC M6_finger_VNCAPa (AA SYZE BY (0.14*2)) < (0.12 + 0.07) OPPOSITE REGION'

数学方程很简单,但可以在一个字符串中多次出现,应该单独评估。

所以我写了一个示例代码,它能够处理这种情况: 也许它不是那么好,但解决问题:

def eval_math_expressions(filelist):
        for line in filelist:
              if re.match('.*[\-|\+|\*|\/].*',line):
                        lindex=int(filelist.index(line))
                        line_list=line.split()
                        exp=[]
                        for word in line_list:
                                if re.match('^\(+\d+',word) or re.match('^[\)+|\d+|\-|\+|\*|\/]',word):
                                        exp.append(word)
                                else:
                                        ready=' '.join(exp)
                                        if ready:
                                                eval_ready=str(eval(ready))
                                                line_new=line.replace(ready,eval_ready)
                                                line=line_new
                                                filelist[lindex]=line
                                        exp=[]
        return filelist

答案 4 :(得分:0)

对于不使用eval的解决方案,这就是我要做的。首先找到字符串中的所有数学表达式,我将其定义为包含空格,括号,数字和操作的字符串,然后删除所有空格的匹配项:

>>> import re
>>> my_str = 'I have 6 * (2 + 3) apples'
>>> exprs = list(re.finditer(r"[\d\.\s\*\+\-\/\(\)]+", my_str))
>>> exprs = [e for e in exprs if len(my_str[e.start():e.end()].strip()) > 0]

接下来,使用this question中使用pyparsingNumericStringParser类评估表达式:

>>> nsp = NumericStringParser()
>>> results = [nsp.eval(my_str[e.start():e.end()]) for e in exprs]
>>> results
[30.0]

然后,要将结果替换回表达式,请按照起始索引对表达式进行反向排序,然后将它们放回原始字符串中:

>>> new_str = my_str
>>> for expr, res in sorted(zip(exprs, results), key=lambda t: t[0].start(), reverse=True):
...     new_str = new_str[:expr.start()] + (" %d " % res) + new_str[expr.end():]
... 
>>> new_str
'I have 30 apples'

答案 5 :(得分:0)

我的选择:

>>> import re
>>> def calc(s):
...     val = s.group()
...     if not val.strip(): return val
...     return " %s " % eval(val.strip(), {'__builtins__': None})
>>> re.sub(r"([0-9\ \.\+\*\-\/(\)]+)", calc, "I have 6 * (2 + 3 ) apples")
'I have 30 apples'

答案 6 :(得分:0)

使用f字符串或切片。

F字符串:f'I have {str(6*(2+3))} apples'

答案 7 :(得分:-1)

[我知道这是一个老问题,但值得在弹出时指出新的有用解决方案]

从python3.6开始,此功能现在内置于语言中,创造了&#34; f-strings&#34;

请参阅:PEP 498 -- Literal String Interpolation

例如(请注意 f 前缀):

f'I have {6 * (2 + 3)} apples'
=> 'I have 30 apples'
color = 'green'
f'I have {6 * (2 + 3)} {color} apples'
=> 'I have 30 green apples'