我有一个关于在字符串中评估数学表达式的问题。例如我的字符串如下:
my_str='I have 6 * (2 + 3) apples'
我想知道如何评估这个字符串并得到以下结果:
'I have 30 apples'
有没有办法做到这一点?
提前致谢。
PS python 的eval
功能在这种情况下没有帮助。尝试使用该eval
函数进行评估时,它引发了错误。
我有一个关于在字符串中评估数学表达式的问题。例如我的字符串如下:
my_str='I have 6 * (2 + 3) apples'
我想知道如何评估这个字符串并得到以下结果:
'I have 30 apples'
有没有办法做到这一点?
提前致谢。
PS python 的eval
功能在这种情况下没有帮助。尝试使用该eval
函数进行评估时,它引发了错误。
这是我的尝试:
>>> 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 等的方程,但我相信它符合问题所在的精神。有关真正可靠的答案,请参阅jeffery_the_wind 发布的问题;但我相信对于这种简单化的案例来说,这可能是矫枉过正。
有时最好简化问题,而不是提出复杂的解决方案。您可能希望通过像这样提供代码来简化问题
my_str='I have {6 * (2 + 3)} apples'
这样,您可以使用简单的正则表达式解析它并评估里面的内容。否则,您将面临很多复杂性。
这是一个非常棘手的问题,一般来说几乎不可能解决。然而,这里有一个简单的方法来解决与示例输入一起工作的问题。
*第 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))
感谢大家的帮助。实际上,与我在实际任务中的示例相比,我提供的示例非常简单。我从文件中读取这些字符串,有时可以有这样的视图:
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
使用 f 字符串或切片。
F弦:f'I have {str(6*(2+3))} apples'
对于不使用 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]
接下来,使用该问题NumericStringParser
中的类评估表达式,该类使用pyparsing:
>>> 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'
我的选择:
>>> 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'
[我知道这是一个老问题,但值得指出新的有用解决方案,因为它们弹出]
从 python3.6 开始,这个功能现在被内置到语言中,被称为“f-strings”。
例如(注意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'