Expanding a logical statement (multiplying out)

前端 未结 2 1095
误落风尘
误落风尘 2021-01-23 21:16

I am looking for a way to expand a logical expression (in a string) of the form:

\'(A or B) and ((C and D) or E)\'

in Python to produce a list of all positive se

相关标签:
2条回答
  • 2021-01-23 21:49

    It sounds as if you want to convert these expressions to Disjunctive Normal Form. A canonical algorithm for doing that is the Quine-McCluskey algorithm; you can find some information about Python implementations thereof in the relevant Wikipedia article and in the answers to this SO question.

    0 讨论(0)
  • 2021-01-23 21:58

    Here's the pyparsing bit, taken from the example SimpleBool.py. First, use infixNotation (formerly known as operatorPrecedence) to define an expression grammar that supports parenthetical grouping, and recognizes precedence of operations:

    from pyparsing import *
    
    term = Word(alphas)
    
    AND = Keyword("and")
    OR = Keyword("or")
    
    expr = infixNotation(term,
        [
        (AND, 2, opAssoc.LEFT),
        (OR, 2, opAssoc.LEFT),
        ])
    
    sample = '(A or B) and ((C and D) or E)'
    
    result = expr.parseString(sample)
    
    from pprint import pprint
    pprint(result.asList())
    

    prints:

    [[['A', 'or', 'B'], 'and', [['C', 'and', 'D'], 'or', 'E']]]
    

    From this, we can see that the expression is at least parsed properly.

    Next, we add parse actions to each level of the hierarchy of operations. For parse actions here, we actually pass classes, so that instead of executing functions and returning some value, the parser will call the class constructor and initializer and return a class instance for the particular subexpression:

    class Operation(object):
        def __init__(self, tokens):
            self._tokens = tokens[0]
            self.assign()
    
        def assign(self):
            """
            function to copy tokens to object attributes
            """
    
        def __repr__(self):
            return self.__class__.__name__ + ":" + repr(self.__dict__)
        __str__ = __repr__
    
    class BinOp(Operation):
        def assign(self):
            self.op = self._tokens[1]
            self.terms = self._tokens[0::2]
            del self._tokens
    
    class AndOp(BinOp):
        pass
    
    class OrOp(BinOp):
        pass
    
    expr = infixNotation(term,
        [
        (AND, 2, opAssoc.LEFT, AndOp),
        (OR, 2, opAssoc.LEFT, OrOp),
        ])
    
    sample = '(A or B) and ((C and D) or E)'
    
    result = expr.parseString(sample)
    pprint(result.asList())
    

    returns:

    [AndOp:{'terms': [OrOp:{'terms': ['A', 'B'], 'op': 'or'}, 
                       OrOp:{'terms': [AndOp:{'terms': ['C', 'D'], 
                                        'op': 'and'}, 'E'], 'op': 'or'}],
    'op': 'and'}]
    

    Now that the expression has been converted to a data structure of subexpressions, I leave it to you to do the work of adding methods to AndOp and OrOp to generate the various combinations of terms that will evaluate overall to True. (Look at the logic in the invregex.py example that inverts regular expressions for ideas on how to add generator functions to the parsed classes to generate the different combinations of terms that you want.)

    0 讨论(0)
提交回复
热议问题