Python 我应该如何使用pyparsing从布尔表达式生成元素列表?
我有一个表示物理对象的布尔表达式列表,可以组合起来表示更大的对象。它们看起来像这样:((A和B)或C)。该对象可以由a和B的组合或仅由C表示。我想生成一个可以用来创建对象的字符串列表。在这种情况下,我想要[[A,B],[C]] Pyparsing看起来非常有趣,所以我决定尝试一下解决这个问题。经过几次失败的尝试后,我决定改编网站上的fourFn.py示例。这就是我到目前为止所做的:Python 我应该如何使用pyparsing从布尔表达式生成元素列表?,python,pyparsing,Python,Pyparsing,我有一个表示物理对象的布尔表达式列表,可以组合起来表示更大的对象。它们看起来像这样:((A和B)或C)。该对象可以由a和B的组合或仅由C表示。我想生成一个可以用来创建对象的字符串列表。在这种情况下,我想要[[A,B],[C]] Pyparsing看起来非常有趣,所以我决定尝试一下解决这个问题。经过几次失败的尝试后,我决定改编网站上的fourFn.py示例。这就是我到目前为止所做的: from pyparsing import Literal, CaselessLiteral, Word, Com
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']])
解析器的构造如下:
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))
expr=Forward()
atom=element.setParseAction(pushFirst)|(lpar+expr+rpar)
expr为了将来的参考,这里有一种方法适用于我的测试用例,但与上面建议的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))
从pyparsing导入文本,Word,可选\
组,零或更多,前进,alphanums
导入ffparser,sys
exprStack=[]
def myAnd(op1、op2):
如果isinstance(op1,str)和isinstance(op2,str):
新列表=[[op1,op2]]
elif isinstance(op1,str):
newlist=op2
[项目。为新列表中的项目插入(0,op1)]
elif isinstance(op2,str):
newlist=op1
[项目1中项目的项目追加(op2)]
其他:
newlist=[op1.为op2中的项追加(项)]
返回新列表
def myOr(op1、op2):
如果isinstance(op1,str)和isinstance(op2,str):
新列表=[[op1],[op2]]
elif isinstance(op1,str):
newlist=op2
newlist.insert(0,[op1])
elif isinstance(op2,str):
newlist=op1
newlist.append([op2])
其他:
新列表=[]
[newlist.append(项目)用于op1中的项目]
[newlist.append(项目)用于op2中的项目]
返回新列表
def推送优先(strg、loc、toks):
exprStack.append(toks[0])
bnf=无
def BNF():
"""
布洛普::“和”|“或”
基因::alphanum
原子::基因|'('expr')'
"""
全球bnf
如果不是bnf:
元素=单词(字母)
andop=文字(“和”)
orop=文字(“或”)
lpar=Literal(“”.suppress()
rpar=Literal(“”)。suppress()
boolop=andop | orop
expr=Forward()
atom=element.setParseAction(pushFirst)|(可选(lpar)+expr+可选(rpar))
expr为了将来的参考,这里有一种方法适用于我的测试用例,但与上面建议的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))
从pyparsing导入文本,Word,可选\
组,零或更多,前进,alphanums
导入ffparser,sys
exprStack=[]
def myAnd(op1、op2):
如果isinstance(op1,str)和isinstance(op2,str):
新列表=[[op1,op2]]
elif isinstance(op1,str):
newlist=op2
[项目。为新列表中的项目插入(0,op1)]
elif isinstance(op2,str):
newlist=op1
[项目1中项目的项目追加(op2)]
其他:
newlist=[op1.为op2中的项追加(项)]
返回新列表
def myOr(op1、op2):
如果isinstance(op1,str)和isinstance(op2,str):
新列表=[[op1],[op2]]
elif isinstance(op1,str):
newlist=op2
newlist.insert(0,[op1])
elif isinstance(op2,str):
newlist=op1
newlist.append([op2])
其他:
新列表=[]
[newlist.append(项目)用于op1中的项目]
[newlist.append(项目)用于op2中的项目]
返回新列表
def推送优先(strg、loc、toks):
exprStack.append(toks[0])
bnf=无
def BNF():
"""
布洛普::“和”|“或”
基因::alphanum
原子::基因|'('expr')'
"""
全球bnf
如果不是bnf:
元素=单词(字母)
andop=文字(“和”)
orop=文字(“或”)
lpar=Literal(“”.suppress()
rpar=Literal(“”)。suppress()
boolop=andop | orop
expr=Forward()
atom=element.setParseAction(pushFirst)|(可选(lpar)+expr+可选(rpar))
expr如果我是你的话,我刚刚创建了一个普通的经典AST,操作数作为节点,操作数作为叶子,然后遍历它来构建我喜欢的结构。在您的例子中,它只是用操作数列表替换“and”节点。它使用pyparsing助手方法OperatorRecessence
,这为您做了大量atom/factor/term工作。py将返回Bool对象的结构,类似于@9000提出的AST,但具有更丰富的对象API,因此您可以直接评估结果。感谢您的评论。我喜欢AST的建议,并且一定会看看SimpleBool.py示例。我确实成功地使上述方法适用于我的测试用例。如果我是你,我刚刚创建了一个简单的经典AST,操作数作为节点,操作数作为叶子,然后遍历它来构建我喜欢的结构。在您的例子中,它只是用操作数列表替换“and”节点。它使用pyparsing助手方法OperatorRecessence
,这为您做了大量atom/factor/term工作。py将返回Bool对象的结构,类似于@9000提出的AST,但具有更丰富的对象API,因此您可以直接评估结果。感谢您的评论。我喜欢AST的建议,并且一定会看看SimpleBool.py示例。我确实设法使上述方法适用于我的测试用例。