如何在Python2中计算字符串中的不等式

如何在Python2中计算字符串中的不等式,python,python-2.7,parsing,eval,Python,Python 2.7,Parsing,Eval,我有一个文本文件(另一个进程的输出,我无法更改),其中包含逻辑比较(只有这三个:>,经过几个小时的工作,我找到了一种获取ast.literal\u eval()的方法开始工作!我的逻辑是查看x>2的两个方面,即x和2,通过literal\u eval评估这两个方面,确保它们是安全的,然后通过我的check()函数运行它,该函数进行评估。对于('def',abc')中的z也一样:首先确保z和('def','abc')都是安全的,然后使用check()函数执行实际的布尔检查 因为我完全信任我的输入,

我有一个文本文件(另一个进程的输出,我无法更改),其中包含逻辑比较(只有这三个:
>,经过几个小时的工作,我找到了一种获取
ast.literal\u eval()的方法
开始工作!我的逻辑是查看
x>2
的两个方面,即
x
2
,通过
literal\u eval
评估这两个方面,确保它们是安全的,然后通过我的
check()
函数运行它,该函数进行评估。对于('def',abc')中的
z也一样
:首先确保
z
('def','abc')
都是安全的,然后使用
check()
函数执行实际的布尔检查

因为我完全信任我的输入,所以我本可以用更简单的
eval()
方法,但我只想加倍小心。并想为所有存在安全问题(用户输入等)且需要安全评估逻辑的人构建一些代码。希望它能帮助某些人

请参阅下面我的完整代码,欢迎提出任何意见/建议

import re
import ast

myStr = "x>2 and y<=30 and z in ('def', 'abc')"
categoricalVars = ('z')
x, y, z = '5', '6', 'abc'
delim = "(\>|\<=|\ in )" # Put in group to find in the func check() which delimiter is used

def pyRules(s):
    """
    Place {} around variable names so that we can str.format() in the func check()
    """
    varName = re.split(delim, s)[0]
    rest = "".join(re.split(delim, s)[1:])
    return "'{" + varName + "}'" + rest

def check(x):
    """
    If operation is > or <= then it is a numeric var, use double literal_eval to
    parse floats e.g. "'5'" (dual quotes) to 5.0. This is equivalent to:
    float(ast.literal_eval(first)). Else it is categorical, just literal_eval once
    """
    first, operation, second = re.split(delim, x)
    if operation == ">":
        return ast.literal_eval(ast.literal_eval(first)) > ast.literal_eval(second)
    elif operation == "<=":
        return ast.literal_eval(ast.literal_eval(first)) <= ast.literal_eval(second)
    elif operation == " in ":
        return ast.literal_eval(first) in ast.literal_eval(second)

# These are my raw rules:
print [pyRules(e) for e in myStr.split(' and ')] 

# These are my processed rules:
print [pyRules(e).format(x='5',y='6',z='abc') for e in myStr.split(' and ')] 

# And these are my final results of logical evaluation:
print [check(pyRules(e).format(x='5',y='6',z='abc')) for e in myStr.split(' and ')] 
重新导入
导入ast
myStr=“x>2和y |\or”:
返回ast.literal_eval(ast.literal_eval(第一))>ast.literal_eval(第二)

elif操作==“2”、“{y}'2”、“'6'
eval()
对于不受信任的字符串是有问题的。否则,它只是在运行代码。请看一看,它可能有一些用处。谢谢@stephernauch!如果没有什么好消息,我将使用
eval()
。@cᴏʟᴅsᴘᴇᴇᴅ 谢谢!乍一看似乎很有希望,我现在正在检查。如果您完全信任您的代码,我认为使用
eval
就可以了。
categoricalVars = ('z')
x, y, z = '5', '6', 'abc'
import re
delim = "(\>|\<=|\ in )" # Put in group to find later which delimiter is used

def pyRules(s):
    varName = re.split(delim, s)[0]
    rest = "".join(re.split(delim, s)[1:])
    if varName in categoricalVars:
        return varName + rest
    else:
        return "float(" + varName + ")" + rest
# Call:
[pyRules(e) for e in myStr.split(' and ')] 
# Result:
['float(x)>2', 'float(y)<=30', "z in ('def', 'abc')"]
[eval(pyRules(e)) for e in myStr.split(' and ')]
# Result:
[True, True, True]
import ast
[ast.literal_eval(pyRules(e)) for e in myStr.split(' and ')]
# Result:
Traceback (most recent call last):

  File "<ipython-input-556-dae16951de03>", line 1, in <module>
    ast.literal_eval(ast.parse(conds[0]))

  File "C:\ProgramData\Anaconda2\lib\ast.py", line 80, in literal_eval
    return _convert(node_or_string)

  File "C:\ProgramData\Anaconda2\lib\ast.py", line 79, in _convert
    raise ValueError('malformed string')

ValueError: malformed string
def pyRules(s):
    varName = re.split(delim, s)[0]
    operation = "".join(re.split(delim, s)[1:])
    if varName in categoricalVars:
        return "'{" + varName + "}'" + operation
    else:
        return "float({" + varName + "})" + operation

rules = [pyRules(e).format(x='5',y='6',z='abc') for e in myStr.split(' and ')] 
# rules is:
['float(5)>2', 'float(6)<=30', "'abc' in ('def', 'abc')"]
def check(x):
    first, operation, second = re.split(delim, x)
    if operation == ">":
        return first > second
    elif operation == "<=":
        return first <= second
    elif operation == " in ":
        return first in second
# Call:
[check(pyRules(e).format(x='5',y='6',z='abc')) for e in myStr.split(' and ')] 
# Result:
[True, False, True]
import re
import ast

myStr = "x>2 and y<=30 and z in ('def', 'abc')"
categoricalVars = ('z')
x, y, z = '5', '6', 'abc'
delim = "(\>|\<=|\ in )" # Put in group to find in the func check() which delimiter is used

def pyRules(s):
    """
    Place {} around variable names so that we can str.format() in the func check()
    """
    varName = re.split(delim, s)[0]
    rest = "".join(re.split(delim, s)[1:])
    return "'{" + varName + "}'" + rest

def check(x):
    """
    If operation is > or <= then it is a numeric var, use double literal_eval to
    parse floats e.g. "'5'" (dual quotes) to 5.0. This is equivalent to:
    float(ast.literal_eval(first)). Else it is categorical, just literal_eval once
    """
    first, operation, second = re.split(delim, x)
    if operation == ">":
        return ast.literal_eval(ast.literal_eval(first)) > ast.literal_eval(second)
    elif operation == "<=":
        return ast.literal_eval(ast.literal_eval(first)) <= ast.literal_eval(second)
    elif operation == " in ":
        return ast.literal_eval(first) in ast.literal_eval(second)

# These are my raw rules:
print [pyRules(e) for e in myStr.split(' and ')] 

# These are my processed rules:
print [pyRules(e).format(x='5',y='6',z='abc') for e in myStr.split(' and ')] 

# And these are my final results of logical evaluation:
print [check(pyRules(e).format(x='5',y='6',z='abc')) for e in myStr.split(' and ')] 
["'{x}'>2", "'{y}'<=30", "'{z}' in ('def', 'abc')"]
["'5'>2", "'6'<=30", "'abc' in ('def', 'abc')"]
[True, True, True]