Python 如何处理用户提供的公式?

Python 如何处理用户提供的公式?,python,Python,我有一个字典,其中包含一组通过web应用程序可用的键值: 我想处理用户提供的公式,如: ((值1+值3)/值4)*100 获取公式计算值与字典中的匹配值的最简单方法是什么 考虑这个例子: #!/usr/bin/python values={'value1':10,'value2':1245,'value3':674365,'value4':65432,'value5':131} formula=raw_input('Please enter formula:') 如果我提供公式“((value

我有一个字典,其中包含一组通过web应用程序可用的键值: 我想处理用户提供的公式,如: ((值1+值3)/值4)*100

获取公式计算值与字典中的匹配值的最简单方法是什么

考虑这个例子:

#!/usr/bin/python
values={'value1':10,'value2':1245,'value3':674365,'value4':65432,'value5':131}
formula=raw_input('Please enter formula:')
如果我提供公式“((value1+value3)/value4)*100”,我如何将value1等映射到字典中的value1并计算结果


干杯,

验证公式和数字值后(例如,通过regexp),您可以执行以下操作:

arr = {'num1':4, 'num2':5, 'num3':7}
formula = '(num1+num2)*num3'

for key, val in arr.items():
    formula = formula.replace(key, str(val))

res = eval(formula)
print res

验证公式和数字值后(例如,通过regexp),您可以执行以下操作:

arr = {'num1':4, 'num2':5, 'num3':7}
formula = '(num1+num2)*num3'

for key, val in arr.items():
    formula = formula.replace(key, str(val))

res = eval(formula)
print res

eval
可用于执行恶意代码

你信任你的用户吗?如果是这样,您可以将
值作为全局dict传递给
eval
。因此,
eval
可以直接计算用户公式,而无需任何额外的字符串操作:

values={'value1':10,'value2':1245,'value3':674365,'value4':65432,'value5':131}
formula=raw_input('Please enter formula:')
values=eval(formula,values)
print(values)
如果您不信任您的潜在用户,您可以使用pyparsing: 以下是Paul McGuire的,封装在类中以便于使用

utils\u parse\u numeric.py:

from __future__ import division
from pyparsing import (Literal,CaselessLiteral,Word,Combine,Group,Optional,
                       ZeroOrMore,Forward,nums,alphas,oneOf)
import math
import operator   

class NumericStringParser(object):
    '''
    Most of this code comes from the fourFn.py pyparsing example

    '''
    def pushFirst(self, strg, loc, toks ):
        self.exprStack.append( toks[0] )
    def pushUMinus(self, strg, loc, toks ):
        if toks and toks[0]=='-': 
            self.exprStack.append( 'unary -' )
    def __init__(self):
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: PI | E | real | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        """
        point = Literal( "." )
        e     = CaselessLiteral( "E" )
        fnumber = Combine( Word( "+-"+nums, nums ) + 
                           Optional( point + Optional( Word( nums ) ) ) +
                           Optional( e + Word( "+-"+nums, nums ) ) )
        ident = Word(alphas, alphas+nums+"_$")       
        plus  = Literal( "+" )
        minus = Literal( "-" )
        mult  = Literal( "*" )
        div   = Literal( "/" )
        lpar  = Literal( "(" ).suppress()
        rpar  = Literal( ")" ).suppress()
        addop  = plus | minus
        multop = mult | div
        expop = Literal( "^" )
        pi    = CaselessLiteral( "PI" )
        expr = Forward()
        atom = ((Optional(oneOf("- +")) +
                 (pi|e|fnumber|ident+lpar+expr+rpar).setParseAction(self.pushFirst))
                | Optional(oneOf("- +")) + Group(lpar+expr+rpar)
                ).setParseAction(self.pushUMinus)       
        factor = Forward()
        factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( self.pushFirst ) )
        term = factor + ZeroOrMore( ( multop + factor ).setParseAction( self.pushFirst ) )
        expr << term + ZeroOrMore( ( addop + term ).setParseAction( self.pushFirst ) )
        self.bnf = expr
        epsilon = 1e-12
        self.opn = { "+" : operator.add,
                "-" : operator.sub,
                "*" : operator.mul,
                "/" : operator.truediv,
                "^" : operator.pow }
        self.fn  = { "sin" : math.sin,
                "cos" : math.cos,
                "tan" : math.tan,
                "abs" : abs,
                "trunc" : lambda a: int(a),
                "round" : round,
                "sgn" : lambda a: abs(a)>epsilon and cmp(a,0) or 0}
    def evaluateStack(self, s ):
        op = s.pop()
        if op == 'unary -':
            return -self.evaluateStack( s )
        if op in "+-*/^":
            op2 = self.evaluateStack( s )
            op1 = self.evaluateStack( s )
            return self.opn[op]( op1, op2 )
        elif op == "PI":
            return math.pi # 3.1415926535
        elif op == "E":
            return math.e  # 2.718281828
        elif op in self.fn:
            return self.fn[op]( self.evaluateStack( s ) )
        elif op[0].isalpha():
            return 0
        else:
            return float( op )
    def eval(self,num_string,parseAll=True):
        self.exprStack=[]
        results=self.bnf.parseString(num_string,parseAll)
        val=self.evaluateStack( self.exprStack[:] )
        return val
这使用
re
模块将my_dict[“numberXXX”]替换为“numberXXX”:

def callback(match):
    num=match.group(1)
    key='number{0}'.format(num)
    val=my_dict[key]
    return str(val)

astr='((number1+number3)/number2)*100'
astr=re.sub('number(\d+)',callback,astr)
下面介绍如何使用NumericStringParser安全地计算数值表达式:

nsp=upn.NumericStringParser()
result=nsp.eval(astr)
print(result)

这比使用eval安全得多。所有无效表达式都将引发pyparsing.ParseException。

eval
可用于执行恶意代码

你信任你的用户吗?如果是这样,您可以将
值作为全局dict传递给
eval
。因此,
eval
可以直接计算用户公式,而无需任何额外的字符串操作:

values={'value1':10,'value2':1245,'value3':674365,'value4':65432,'value5':131}
formula=raw_input('Please enter formula:')
values=eval(formula,values)
print(values)
如果您不信任您的潜在用户,您可以使用pyparsing: 以下是Paul McGuire的,封装在类中以便于使用

utils\u parse\u numeric.py:

from __future__ import division
from pyparsing import (Literal,CaselessLiteral,Word,Combine,Group,Optional,
                       ZeroOrMore,Forward,nums,alphas,oneOf)
import math
import operator   

class NumericStringParser(object):
    '''
    Most of this code comes from the fourFn.py pyparsing example

    '''
    def pushFirst(self, strg, loc, toks ):
        self.exprStack.append( toks[0] )
    def pushUMinus(self, strg, loc, toks ):
        if toks and toks[0]=='-': 
            self.exprStack.append( 'unary -' )
    def __init__(self):
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: PI | E | real | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        """
        point = Literal( "." )
        e     = CaselessLiteral( "E" )
        fnumber = Combine( Word( "+-"+nums, nums ) + 
                           Optional( point + Optional( Word( nums ) ) ) +
                           Optional( e + Word( "+-"+nums, nums ) ) )
        ident = Word(alphas, alphas+nums+"_$")       
        plus  = Literal( "+" )
        minus = Literal( "-" )
        mult  = Literal( "*" )
        div   = Literal( "/" )
        lpar  = Literal( "(" ).suppress()
        rpar  = Literal( ")" ).suppress()
        addop  = plus | minus
        multop = mult | div
        expop = Literal( "^" )
        pi    = CaselessLiteral( "PI" )
        expr = Forward()
        atom = ((Optional(oneOf("- +")) +
                 (pi|e|fnumber|ident+lpar+expr+rpar).setParseAction(self.pushFirst))
                | Optional(oneOf("- +")) + Group(lpar+expr+rpar)
                ).setParseAction(self.pushUMinus)       
        factor = Forward()
        factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( self.pushFirst ) )
        term = factor + ZeroOrMore( ( multop + factor ).setParseAction( self.pushFirst ) )
        expr << term + ZeroOrMore( ( addop + term ).setParseAction( self.pushFirst ) )
        self.bnf = expr
        epsilon = 1e-12
        self.opn = { "+" : operator.add,
                "-" : operator.sub,
                "*" : operator.mul,
                "/" : operator.truediv,
                "^" : operator.pow }
        self.fn  = { "sin" : math.sin,
                "cos" : math.cos,
                "tan" : math.tan,
                "abs" : abs,
                "trunc" : lambda a: int(a),
                "round" : round,
                "sgn" : lambda a: abs(a)>epsilon and cmp(a,0) or 0}
    def evaluateStack(self, s ):
        op = s.pop()
        if op == 'unary -':
            return -self.evaluateStack( s )
        if op in "+-*/^":
            op2 = self.evaluateStack( s )
            op1 = self.evaluateStack( s )
            return self.opn[op]( op1, op2 )
        elif op == "PI":
            return math.pi # 3.1415926535
        elif op == "E":
            return math.e  # 2.718281828
        elif op in self.fn:
            return self.fn[op]( self.evaluateStack( s ) )
        elif op[0].isalpha():
            return 0
        else:
            return float( op )
    def eval(self,num_string,parseAll=True):
        self.exprStack=[]
        results=self.bnf.parseString(num_string,parseAll)
        val=self.evaluateStack( self.exprStack[:] )
        return val
这使用
re
模块将my_dict[“numberXXX”]替换为“numberXXX”:

def callback(match):
    num=match.group(1)
    key='number{0}'.format(num)
    val=my_dict[key]
    return str(val)

astr='((number1+number3)/number2)*100'
astr=re.sub('number(\d+)',callback,astr)
下面介绍如何使用NumericStringParser安全地计算数值表达式:

nsp=upn.NumericStringParser()
result=nsp.eval(astr)
print(result)

这比使用eval安全得多。所有无效表达式都将引发pyparsing.ParseException。

感谢您的所有输入。我个人发现拉科波的回答最适合我的情况

以下是解决方案的大致思路:

import sys

values={'one':10,'two':1245,'three':674365,'four':65432,'five':131}
print str(values)

formula=raw_input('Please enter formula:')

for key, val in values.items():
        formula = formula.replace(key, str(val))

whitelist=[ '+','-','/','*','^','(',')' ]

to_evaluate=re.findall('\D',formula)
to_evaluate=list(set(to_evaluate))

for element in to_evaluate:
        if not element in whitelist:
                print "Formula contains an invalid character: "+str(element)
                sys.exit(1)


print eval(formula)

谢谢大家的意见。我个人发现拉科波的回答最适合我的情况

以下是解决方案的大致思路:

import sys

values={'one':10,'two':1245,'three':674365,'four':65432,'five':131}
print str(values)

formula=raw_input('Please enter formula:')

for key, val in values.items():
        formula = formula.replace(key, str(val))

whitelist=[ '+','-','/','*','^','(',')' ]

to_evaluate=re.findall('\D',formula)
to_evaluate=list(set(to_evaluate))

for element in to_evaluate:
        if not element in whitelist:
                print "Formula contains an invalid character: "+str(element)
                sys.exit(1)


print eval(formula)

你的意图有点不清楚。公式确定了吗?你能举一个输入和输出的例子吗?你是对的,我已经更新了这个问题,使它更清楚了。你的意图有点不清楚。公式确定了吗?你能举一个输入和输出的例子吗?你是对的,我已经更新了一点问题,使它更清楚,这很有趣。。。我丢失了两个零件,更换和评估。。。我将对此进行研究,但它看起来确实是一个选项。如果用户输入公式,请确保针对任意代码执行进行验证。如果只需要算术运算,只需检查forumla在替换后是否不包含任何字符。确保清除输入,或仅从受信任的输入读取。eval()将运行任何东西,即使它意味着对您的计算机。这很有趣。。。我丢失了两个零件,更换和评估。。。我将对此进行研究,但它看起来确实是一个选项。如果用户输入公式,请确保针对任意代码执行进行验证。如果只需要算术运算,只需检查forumla在替换后是否不包含任何字符。确保清除输入,或仅从受信任的输入读取。eval()将运行任何操作,即使这意味着要针对您的计算机。