[英]Parsing logical expressions
我有一个任务,我必须根据用户指定的逻辑表达式过滤 Pandas DataFrame。 现在,我看到了一个我想使用的名为 PyParser 或 LARK 的模块,但我似乎不知道如何设置它们。
我有几个运算符,如CONTAINS
、 EQUAL
、 FUZZY_MATCH
等。另外,我想将一些表达式组合成更复杂的表达式。
示例表达式:
ColumnA CONTAINS [1, 2, 3] AND (ColumnB FUZZY_MATCH 'bla' OR ColumnC EQUAL 45)
因此,我希望有一些结构化的 Dict 或 List 具有操作级别的操作顺序,以便执行它们。 因此,此示例表达式的预期结果将类似于:
[['ColumnA', 'CONTAINS', '[1, 2, 3]'], 'AND', [['ColumnB', 'FUZZY_MATCH', 'bla'], OR, ['ColumnC', 'EQUAL', '45']]]
或以字典的形式:
{
'EXPR1': {
'col': 'ColumnA',
'oper': 'CONTAINS',
'value': '[1, 2, 3]']
},
'OPERATOR': 'AND',
'EXPR2': {
'EXPR21': {
'col': 'ColumnB',
'oper': 'FUZZY_MATCH',
'value': 'bla'
},
'OPERATOR': OR,
'EXPR22': {
'col': 'ColumnC',
'oper': 'EQUAL',
'value': '45'
}
}
}
或类似的东西。 如果您有更好的方法来构建结果,我愿意接受建议。 我对此很陌生,所以我相当肯定这可以改进。
有趣的问题:)
似乎是调车场算法的一个相对简单的应用。
我在这里编写了代码来解析像"((20 - 10 ) * (30 - 20) / 10 + 10 ) * 2"
这样的表达式。
import re
def tokenize(str):
return re.findall("[+/*()-]|\d+", expression)
def is_number(str):
try:
int(str)
return True
except ValueError:
return False
def peek(stack):
return stack[-1] if stack else None
def apply_operator(operators, values):
operator = operators.pop()
right = values.pop()
left = values.pop()
values.append(eval("{0}{1}{2}".format(left, operator, right)))
def greater_precedence(op1, op2):
precedences = {"+": 0, "-": 0, "*": 1, "/": 1}
return precedences[op1] > precedences[op2]
def evaluate(expression):
tokens = tokenize(expression)
values = []
operators = []
for token in tokens:
if is_number(token):
values.append(int(token))
elif token == "(":
operators.append(token)
elif token == ")":
top = peek(operators)
while top is not None and top != "(":
apply_operator(operators, values)
top = peek(operators)
operators.pop() # Discard the '('
else:
# Operator
top = peek(operators)
while top is not None and top != "(" and greater_precedence(top, token):
apply_operator(operators, values)
top = peek(operators)
operators.append(token)
while peek(operators) is not None:
apply_operator(operators, values)
return values[0]
def main():
expression = "((20 - 10 ) * (30 - 20) / 10 + 10 ) * 2"
print(evaluate(expression))
if __name__ == "__main__":
main()
我认为我们可以稍微修改代码以使其适用于您的情况:
tokenize()
中对输入字符串进行标记的方式。ColumnA CONTAINS [1, 2, 3] AND (ColumnB FUZZY_MATCH 'bla' OR ColumnC EQUAL 45)
,我们需要一个标记列表:['ColumnA', 'CONTAINS', '[1, 2, 3]', 'AND', '(', 'ColumnB', 'FUZZY_MATCH', "'bla'", 'OR', 'ColumnC', 'EQUAL', '45', ')']
。is_number()
function 以检测ColumnA
、 [1, 2, 3]
等内容。CONTAINS
/ FUZZY_MATCH
/ EQUAL
、运算符AND
/ OR
和括号(
/ )
之外的所有内容。op1
在['CONTAINS', 'EQUAL', ..]
之间并且op2
是['AND', 'OR']
则修改greater_precedence(op1, op2)
以返回 true 。AND
/ OR
之前评估contains
和equals
。apply_operator(operators, values)
以实现如何评估 boolean 表达式ColumnA CONTAINS [1, 2, 3]
或表达式true AND false
的逻辑。CONTAINS
/ FUZZY_MATCH
/ EQUAL
/ AND
/ OR
等都是运算符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.