1

我需要转一串形式:

'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()

只要在迭代期间执行展平步骤,这似乎工作得很好。

4

2 回答 2

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)
于 2013-04-24T09:33:18.387 回答
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]]]]
于 2013-04-24T13:44:54.313 回答