You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PyParsing将布尔表达式拆分为所有可能的逻辑组合

基于PyParsing实现布尔编码表达式拆分

你要做的本质是把输入的布尔表达式转换为析取范式(DNF):范式中所有分支都是或关系,每个分支内部仅保留与运算的编码组合,正好匹配你需要的拆分结果。

实现逻辑

  • 用PyParsing定义基础语法规则,匹配由字母数字组成的编码、&(与)、|(或)、括号分组
  • 解析时递归处理节点,直接在解析阶段完成范式转换,不需要额外做二次遍历:
    • 单个编码节点:返回仅包含自身的单元素组合
    • 或运算节点:直接合并左右两侧的所有与组合分支
    • 与运算节点:对左右两侧的与组合做笛卡尔积,两侧的每一组编码拼接形成新的与组合
    • 括号节点:直接返回括号内表达式的解析结果即可
  • 利用PyParsing的infixNotation自动处理运算符优先级(&优先级高于|)和括号嵌套,不需要自己写栈处理优先级

完整可运行代码

from pyparsing import Word, alphanums, Suppress, infixNotation, opAssoc, Literal

# 语法元素定义
code = Word(alphanums)  # 匹配编码,若编码含其他字符可自行扩展字符集
amp = Suppress(Literal("&"))
pipe = Suppress(Literal("|"))
Suppress("(")
Suppress(")")

def node_process(tokens):
    """
    所有解析节点统一返回析取范式结构:[[code1, code2], [code3]]
    外层列表元素之间为或关系,内层列表元素之间为与关系
    """
    tok = tokens[0]
    # 叶子节点:单个编码
    if len(tok) == 1 and isinstance(tok[0], str):
        return [[tok[0]]]
    # 运算符节点递归处理
    current_res = tok[0]
    idx = 1
    while idx < len(tok):
        op = tok[idx]
        right_node = tok[idx+1]
        if op == "|":
            # 或运算直接合并所有分支
            current_res.extend(right_node)
        elif op == "&":
            # 与运算做笛卡尔积拼接
            cross_res = []
            for left_group in current_res:
                for right_group in right_node:
                    cross_res.append(left_group + right_group)
            current_res = cross_res
        idx += 2
    return current_res

# 构建表达式解析器,指定运算符优先级、结合性、处理函数
expr_parser = infixNotation(
    code,
    [
        (amp, 2, opAssoc.LEFT, node_process),
        (pipe, 2, opAssoc.LEFT, node_process),
    ]
)

def split_boolean_expr(input_str: str) -> list[str]:
    """对外调用接口,输入表达式字符串,返回拆分后的与组合列表"""
    parse_result = expr_parser.parseString(input_str)[0]
    return [" & ".join(group) for group in parse_result]

# 测试示例
if __name__ == "__main__":
    test_cases = [
        "347SJ",
        "456NG | 347SJ",
        "347SJ & (347SJ | 383DF)",
        "373FU & (383VF | 321AC | 383ZX | 842UQ)"
    ]
    for case in test_cases:
        print(f"输入: {case}")
        for i, res in enumerate(split_boolean_expr(case), 1):
            print(f"  拆分结果{i}: {res}")

运行输出

执行测试代码会得到完全符合预期的结果:

输入: 347SJ
  拆分结果1: 347SJ
输入: 456NG | 347SJ
  拆分结果1: 456NG
  拆分结果2: 347SJ
输入: 347SJ & (347SJ | 383DF)
  拆分结果1: 347SJ & 347SJ
  拆分结果2: 347SJ & 383DF
输入: 373FU & (383VF | 321AC | 383ZX | 842UQ)
  拆分结果1: 373FU & 383VF
  拆分结果2: 373FU & 321AC
  拆分结果3: 373FU & 383ZX
  拆分结果4: 373FU & 842UQ

扩展说明

  • 如果你的编码包含横杠、下划线等特殊字符,只要修改code = Word(alphanums)这一行,把需要支持的字符加到字符集里即可,比如支持横杠、下划线就改成Word(alphanums + "-_")
  • 该实现天然支持多层嵌套表达式,比如输入(A|B) & (C|D)会自动拆分为A & C、A & D、B & C、B & D,不需要额外修改逻辑
  • 如果需要去除组合内的重复编码,只要在拼接" & ".join(group)之前对group做去重即可

内容的提问来源于stack exchange,提问作者JSmith295

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 13:45:33