我有一个关于在字符串中评估数学表达式的问题。 例如,我的字符串如下:
my_str='I have 6 * (2 + 3) apples'
我想知道如何评估此字符串并获得以下结果:
'I have 30 apples'
有没有办法做到这一点?
提前致谢。
P.S。在这种情况下,python的eval
函数没有帮助。在尝试使用eval
函数进行评估时,它引发了错误。
答案 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中使用pyparsing的NumericStringParser
类评估表达式:
>>> 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'