我该如何使用pyparsing从布尔表达式生成元素列表?
我有一堆布尔表达式,这些表达式代表可以组合在一起形成更大物体的物理对象。它们看起来像这样:((A and B) or C)。这个对象可以通过A和B的组合来表示,也可以单独用C来表示。我想生成一个字符串的列表列表,用来创建这个对象。在这个例子中,我想要的是[[A,B], [C]]。
我觉得Pyparsing挺有意思的,所以决定用它来解决这个问题。在几次失败的尝试后,我决定改编网站上的fourFn.py示例。这是我目前的进展:
from pyparsing import Literal, CaselessLiteral, Word, Combine, \
Group, Optional, ZeroOrMore, Forward, alphanums
exprStack = []
def myAnd(op1, op2):
if isinstance(op1, str):
return([op1, op2])
else:
return op1.append(op2)
def myOr(op1, op2):
if isinstance(op1, str):
return([[op1], [op2]])
else:
return op1.append([op2])
def pushFirst(strg, loc, toks):
exprStack.append(toks[0])
bnf = None
def BNF():
"""
boolop :: 'and' | 'or'
gene :: alphanum
atom :: gene | '(' expr ')'
"""
global bnf
if not bnf:
element = Word(alphanums)
andop = Literal( "and" )
orop = Literal( "or" )
lpar = Literal( "(" ).suppress()
rpar = Literal( ")" ).suppress()
boolop = andop | orop
expr = Forward()
atom = ((element | lpar + expr + rpar).setParseAction(pushFirst) | (lpar + expr.suppress() + rpar))
expr << atom + ZeroOrMore((boolop + expr).setParseAction(pushFirst))
bnf = expr
return bnf
# map operator symbols to corresponding arithmetic operations
fn = {"or": myOr,
"and": myAnd}
def evaluateStack( s ):
op = s.pop()
if op in fn:
op2 = evaluateStack(s)
op1 = evaluateStack(s)
return fn[op](op1, op2)
else:
return op
if __name__ == "__main__":
def test(s, expVal):
global exprStack
exprStack = []
results = BNF().parseString(s)
val = evaluateStack(exprStack[:])
if val == expVal:
print s, "=", val, results, "=>", exprStack
else:
print "!!! "+s, val, "!=", expVal, results, "=>", exprStack
test("((A and B) or C)", [['A','B'], ['C']])
test("(A and B) or C", [['A','B'], ['C']])
test("(A or B) and C", [['A', 'C'], ['B', 'C']])
test("A and B", ['A', 'B'])
test("A or B", [['A'], ['B']])
前面三个测试在这里失败了,只返回每个括号内表达式的第一个元素。A会被多次推入栈中。看起来我修改fourFn.py的方式破坏了我的脚本处理这些组合的能力。有没有更好的方法来解决这个问题呢?
编辑 喝了一杯咖啡后,我意识到我遇到的问题其实很容易解决。我的新and和or函数如下:
def myAnd(op1, op2):
if isinstance(op1, str) and isinstance(op2, str):
newlist = [op1, op2]
elif isinstance(op1, str):
newlist = [op1]
newlist.append(op2)
elif isinstance(op2, str):
newlist = op1
newlist.append(op2)
else:
newlist = [op1.append(item) for item in op2]
return newlist
def myOr(op1, op2):
if isinstance(op1, str) and isinstance(op2, str):
newlist = [[op1], [op2]]
r
elif isinstance(op1, str):
newlist = [op1]
newlist.append([op2])
elif isinstance(op2, str):
newlist = [op1]
newlist.append([op2])
else:
newlist = [op1, [op2]]
return newlist1
解析器的构建方式如下:
expr = Forward()
atom = element.setParseAction(pushFirst) | (lpar + expr + rpar)
expr << atom + ZeroOrMore((boolop + expr).setParseAction(pushFirst))
一个新的、更有趣的问题是如何处理像这样(A or B)和C的情况。结果应该是[[A, C], [B, C]]。有没有一种典型的pyparsing方法来处理这个问题呢?
1 个回答
0
为了将来参考,这里有一种方法,它适用于我的测试案例,但与上面提到的抽象语法树(AST)方法有所不同:
from pyparsing import Literal, Word, Optional, \
Group, ZeroOrMore, Forward, alphanums
import ffparser, sys
exprStack = []
def myAnd(op1, op2):
if isinstance(op1, str) and isinstance(op2, str):
newlist = [[op1, op2]]
elif isinstance(op1, str):
newlist = op2
[item.insert(0, op1) for item in newlist]
elif isinstance(op2, str):
newlist = op1
[item.append(op2) for item in op1]
else:
newlist = [op1.append(item) for item in op2]
return newlist
def myOr(op1, op2):
if isinstance(op1, str) and isinstance(op2, str):
newlist = [[op1], [op2]]
elif isinstance(op1, str):
newlist = op2
newlist.insert(0, [op1])
elif isinstance(op2, str):
newlist = op1
newlist.append([op2])
else:
newlist = []
[newlist.append(item) for item in op1]
[newlist.append(item) for item in op2]
return newlist
def pushFirst(strg, loc, toks):
exprStack.append(toks[0])
bnf = None
def BNF():
"""
boolop :: 'and' | 'or'
gene :: alphanum
atom :: gene | '(' expr ')'
"""
global bnf
if not bnf:
element = Word(alphanums)
andop = Literal( "and" )
orop = Literal( "or" )
lpar = Literal( "(" ).suppress()
rpar = Literal( ")" ).suppress()
boolop = andop | orop
expr = Forward()
atom = element.setParseAction(pushFirst) | (Optional(lpar) + expr + Optional(rpar))
expr << atom + ZeroOrMore((boolop + expr).setParseAction(pushFirst))