Note that there are some explanatory texts on larger screens.

plurals
  1. POHow should I pyparsing to generate lists of elements from Boolean expressions?
    primarykey
    data
    text
    <p>I have a list of Boolean expressions that represent physical objects that can be combined to represent larger objects. They look something like this: ((A and B) or C). This object can be represented by a combination of A and B or by C alone. I would like to generate a list of lists of strings that can be used to create the object. In this case I want [[A,B], [C]]. </p> <p>Pyparsing looks pretty intriguing so I've decided to give it a shot for this problem. After a few failed attempts I've settled on adapting the fourFn.py example from the website. This is what I have so far:</p> <pre><code>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 &lt;&lt; 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, "=&gt;", exprStack else: print "!!! "+s, val, "!=", expVal, results, "=&gt;", 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']]) </code></pre> <p>The first three tests fail here and only return the first element of each expression in parentheses. A will get pushed to the stack multiple times. It seems that the way I modified fourFn.py has broken my script's ability to handle these groups. Is there a better way to approach this problem?</p> <p><strong>edit</strong> After a cup of coffee I realized the problems I was having were pretty easy to solve. My new and and or functions are as follows:</p> <pre><code>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 </code></pre> <p>And the parser is constructed as follows:</p> <pre><code>expr = Forward() atom = element.setParseAction(pushFirst) | (lpar + expr + rpar) expr &lt;&lt; atom + ZeroOrMore((boolop + expr).setParseAction(pushFirst)) </code></pre> <p>A new and more interesting question involves how to deal with a case like this (A or B) and C. The result should be [[A, C], [B, C]]. Is there a typical pyparsing way of dealing with this issue?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload