使用 Python 在逻辑字符串中获取 "AND" 中的元素

get elements in "AND" in logic string with Python

我想解析逻辑字符串并获取 "and" 逻辑中的所有元素组合。 例如,对于字符串 '( A and ( B or C ) )' 我应该得到 [[A,B],[A,C]] 而对于字符串 '( A and B and ( C or D and F )或 F 和 G )' 我应该得到 [[A,B,C],[A,B,D,F],[F,G]].

我正在尝试使用 pyparsing。在 post here parsing a complex logical expression in pyparsing in a binary tree fashion 之后,我设法得到一个嵌套列表,其中的字母根据偏好进行分组("and" 优先于 "or",括号会覆盖它):

import pyparsing as pp

complex_expr = pp.Forward()
vars = pp.Word(pp.alphas, pp.alphanums + "_") | pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?").setName('proteins')
clause = pp.Group(vars ^ (pp.Suppress("(") + complex_expr + pp.Suppress(")") ))

expr = pp.operatorPrecedence(clause,[
                            ("and", 2, pp.opAssoc.LEFT, ),
                            ("or", 2, pp.opAssoc.LEFT, ),])
#print expr
complex_expr << expr
parseresult=complex_expr.parseString('( A and B and ( C or D and F ) or F and G )')
print parseresult

给出:

[[[[['A'], 'and', ['B'], 'and', [[['C'], 'or', [['D'], 'and', ['F']]]]], 'or', [['F'], 'and', ['G']]]]]

现在我该如何处理这个结果来获得想要的输出?如果有任何帮助,我将不胜感激。我尝试了 pyparsing,但我对其他可能更好的模块持开放态度。

提前致谢。

Python 图书馆将为我们提供一点帮助:

import re
import itertools

让我们编写所需的函数:

def analyse(expression):
    # Find all used symbols
    symbols = set(re.findall(r"\b[A-Z]\b", expression))
    # Find all combinations of symbols and values
    mappings = (dict(zip(symbols, values)) for values in itertools.product([False, True], repeat=len(symbols)))
    # Select combinations that make the whole expression true
    solutions = [sorted(name for name in mapping if mapping[name]) for mapping in mappings if eval(expression, None, mapping)]
    # Filter out redundant solutions
    return sorted(s1 for s1 in solutions if not any(set(s1) > set(s2) for s2 in solutions))

让我们测试一下:

assert analyse("( A and ( B or C ) )") == [["A", "B"], ["A", "C"]]
assert analyse("( A and B and ( C or D and F ) or F and G )") == [["A", "B", "C"], ["A", "B", "D", "F"], ["F", "G"]]

源码中有注释。不管怎样,主要步骤是:

  • 表达式变量被发现为单字符大写名称。
  • 每个变量可以是 True 或 False。我们找到所有组合。
  • 我们select只有这样的组合才能使整个表达式为真。
  • 我们只保留最小解,即那些不是其他解的超集的解。

非常感谢你提出了一个很好的问题。 Python 的 itertools 总是给我惊喜。 ;-)