ValueError: malformed string when using ast.literal_eval

前端 未结 5 1737
眼角桃花
眼角桃花 2020-11-28 14:08

It is widely known that using eval() is a potential security risk so the use of ast.literal_eval(node_or_string) is promoted

However In python 2.7 it re

5条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-28 14:51

    It is not too hard to use pyparsing to cobble together a simple expression evaluator.

    Suppose you want to eval expression, including parens, of the type of expressions of the following:

    2+3
    4.0^2+5*(2+3+4)
    1.23+4.56-7.890
    (1+2+3+4)/5
    1e6^2/1e7
    

    This simplification of the SimpleCalc example:

    import pyparsing as pp
    import re
    
    ex='''\
    2+3
    4.0^2+5*(2+3+4)
    1.23+4.56-7.890
    (1+2+3+4)/5
    1e6^2/1e7'''
    
    e = pp.CaselessLiteral('E')
    dec, plus, minus, mult, div, expop=map(pp.Literal,'.+-*/^')
    addop  = plus | minus
    multop = mult | div
    lpar, rpar=map(pp.Suppress,'()')
    p_m = plus | minus
    
    num = pp.Word(pp.nums) 
    integer = pp.Combine( pp.Optional(p_m) + num )
    floatnumber = pp.Combine( integer +
                           pp.Optional( dec + pp.Optional(num) ) +
                           pp.Optional( e + integer ) )
    
    stack=[]
    def pushFirst(s, l, t):
        stack.append( t[0] )
    
    expr=pp.Forward()
    atom = ((floatnumber | integer).setParseAction(pushFirst) | 
             ( lpar + expr.suppress() + rpar )
           )
    
    factor = pp.Forward()
    factor << atom + pp.ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
    
    term = factor + pp.ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
    expr << term + pp.ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )    
    
    pattern=expr+pp.StringEnd()
    
    opn = { "+" : ( lambda a,b: a + b ),
            "-" : ( lambda a,b: a - b ),
            "*" : ( lambda a,b: a * b ),
            "/" : ( lambda a,b: a / b ),
            "^" : ( lambda a,b: a ** b ) }
    
    def evaluateStack(stk):
        op = stk.pop()
        if op in "+-*/^":
            op2 = evaluateStack(stk)
            op1 = evaluateStack(stk)
            return opn[op](op1, op2)
        elif re.search('^[-+]?[0-9]+$',op):
            return int(op)
        else:
            return float(op)     
    
    for line in ex.splitlines():
        parse=pattern.parseString(line)   
        s=stack[:]
        print('"{}"->{} = {}'.format(line,s,evaluateStack(stack)))   
    

    Prints:

    "2+3"->['2', '3', '+'] = 5
    "4.0^2+5*(2+3+4)"->['4.0', '2', '^', '5', '2', '3', '+', '4', '+', '*', '+'] = 61.0
    "1.23+4.56-7.890"->['1.23', '4.56', '+', '7.890', '-'] = -2.1000000000000005
    "(1+2+3+4)/5"->['1', '2', '+', '3', '+', '4', '+', '5', '/'] = 2.0
    "1e6^2/1e7"->['1E6', '2', '^', '1E7', '/'] = 100000.0
    

提交回复
热议问题