评估字符串内的数学表达式

时间:2014-05-13 01:14:40

标签: python regex

我的问题非常简单,假设我有一个像s = 'line $sin(2*x) $x*cos(x) $x'这样的字符串,我知道其他地方的x(例如1.0)的值。现在我想评估字符串,使它变成s = line 0.909 -0.416 1.0'。你可以看到字符串s中有三个数学表达式:每个以$符号开头,以空格或行尾结束。

这个想法应该很简单:使用正则表达式和re.sub函数。我之前对正则表达式一无所知,经过一两个小时我就知道了它的基本原理,但仍然无法弄清楚如何获得一个匹配三个表达式的正确模式,每个表达式都是独立的。如果我成功了,剩下的部分很简单,使用eval()计算表达式,转换为字符串,并汇编要返回的整个字符串。我想出的代码如下。

import re
from math import *

# parameters
x = 1.0
# test strings
s = 'line $sin(2*x) $x*cos(x) $x'

p = '\$[\s+]'

def replacer(s):
    if s.startswith('$'):
        return eval(s[1:])
    else:
        return "ERROR"

print re.sub(p,replacer,s)

我确信正则表达式是错误的,因为它没有捕获三种模式,我用不同的模式进行了多次实验......有人可以帮助我获得一个工作模式吗?然后我想我可以继续其余的事情了。 更新:问题已解决,请参阅下面的选定答案。

1 个答案:

答案 0 :(得分:2)

您的第一个问题是您在正则表达式中使用[\s+],它只会与空格或+符号匹配一次。
你需要的正确表达式是\$(\S+),它将除$符号之外的所有内容放入捕获组中供以后使用。

其次,您需要以pythonic方式开始编写Python。使用您的值和表达式行将随机变量放在所有地方是不可重用的 相反,将重复变量封装在函数的范围内。从长远来看,这将不那么令人头痛。

此实例中所需的正则表达式函数不是re.sub,而是re.findall。此函数遍历字符串中的所有匹配项。

你会注意到我在使用之前编译了正则表达式,这只是在这个例子中允许更清晰的代码。

最后,我们遍历了一个非常简单的list()数据类型的正则表达式匹配。

如您所见,您只需在任何表达式和任意值上调用evaluate_expression()函数。

import re
from math import *


def evaluate_expression(equation, **kwargs):
    for key in kwargs:
        exec key + " = " + str(kwargs[key])  # Creates x variable
    parser = re.compile(r'\$(\S+)')
    expressions = parser.findall(equation)
    for expression in expressions:
        print eval(expression)

evaluate_expression('line $sin(2*x) $x*cos(x) $x', x=1.0)