我需要转换表单的字符串:
'a==1&&(b==2||(c==3||d==4&&e==5)&&f==6)||(g==7&&h==8)'
进入sqlalchemy逻辑进行过滤(通过or_
和and_
)。第一步实际上是将字符串解析为有用的东西。我想将其纳入表格:
['a==1','&&',['b==2','||',['c==3','||','d==4','&&','e==5'],'&&','f==6'],'||',['g==7','&&','h==8']]
然后递归地逐步解析它。不幸的是,我在解析这个解析步骤时遇到了麻烦,以前从未使用过pyparsing。
编辑(解决方案)
我无法在so
或interblag上找到直接的解决方案,但经过相当多的挖掘文档后,我设法将以下简单表达式放在一起:
from pyparsing import Word, alphanums, nestedExpr
content = Word( alphanums + '=' ) | '||' | '&&'
unnester = nestedExpr( content = content )
a = 'a==3||b==1&&(c==4||(d==1||e==5)&&f==9)'
unnester.parseString( '(' + a + ')' ).asList()
只要在迭代期间执行展平步骤,这似乎工作得很好。
答案 0 :(得分:3)
我还没有真正使用pyparsing
,但是这里有一个直接的python实现,可以做你想要的:
import re
from collections import namedtuple
TOKENIZER = re.compile(r"\w+==\w+|&&|\|\||[()]").findall
Node = namedtuple("Node", ["parent", "children"])
def syntax_tree(text, tokenizer, brackets):
root = cur_node = Node(None, [])
stack = []
for token in tokenizer(text):
if token == brackets["("]:
stack.append(token)
new_node = Node(cur_node, [])
cur_node.children.append(new_node)
cur_node = new_node
elif token == brackets[")"]:
if stack and stack.pop() == brackets[")"]:
cur_node = cur_node.parent
else:
raise Exception("Parse error: unmatched parentheses")
else:
cur_node.children.append(token)
if stack:
raise Exception("Parse error: unmatched parentheses")
return root
def listify(root):
if isinstance(root, Node):
return [listify(item) for item in root.children]
else:
return root
if __name__ == "__main__":
expr = "a==1&&(b==2||(c==3||d==4&&e==5)&&f==6)||(g==7&&h==8)"
tree = syntax_tree(expr, TOKENIZER, {"(": "(", ")": ")"})
obj = listify(tree)
答案 1 :(得分:1)
Pyparsing具有用于解析括号分组操作的内置函数,包括识别运算符的优先级,称为infixNotation
(以前称为operatorPrecedence
)。了解如何在此示例代码中使用它来解析示例表达式:
from pyparsing import Word, alphas, nums, oneOf, Group, infixNotation, opAssoc
sample = 'a==1&&(b==2||(c==3||d==4&&e==5)&&f==6)||(g==7&&h==8)'
# define some basic elements
varname = Word(alphas)
integer = Word(nums).setParseAction(lambda t:int(t[0]))
# Use varname and integer to define a comparison expression
comparisonOp = oneOf("< == > <= >= !=")
term = varname | integer
comparisonExpr = Group(term + comparisonOp + term)
# Use pyparsing builtin 'infixNotation' to implement parser for
# parenthetically grouped expression of various operators (formerly
# named 'operatorPrecedence')
logicalExpr = infixNotation(comparisonExpr,
[
('&&', 2, opAssoc.LEFT),
('||', 2, opAssoc.LEFT),
])
# parse out your sample expression, use pprint to do some pretty-printing
import pprint
pprint.pprint(logicalExpr.parseString(sample).asList())
打印:
[[[['a', '==', 1],
'&&',
[['b', '==', 2],
'||',
[[['c', '==', 3], '||', [['d', '==', 4], '&&', ['e', '==', 5]]],
'&&',
['f', '==', 6]]]],
'||',
[['g', '==', 7], '&&', ['h', '==', 8]]]]