如何用pyparsing库解析含隐式AND的可选运算符?
解析含隐式AND的布尔表达式问题
需要解析类似alpha OR beta gamma的字符串,其中相邻术语(如beta和gamma)之间的缺失运算符为隐式AND。现有代码使用pyparsing实现,但无法识别隐式AND,当前输入alpha OR beta gamma的输出仅为[BinaryOp(OR, Term(alpha), Term(beta))],遗漏了gamma和隐式AND。
原有代码:
import pyparsing as pp class Term: def __init__(self, tokens: pp.ParseResults): self.value = str(tokens[0]) def __repr__(self) -> str: return f"Term({self.value})" class BinaryOp: def __init__(self, tokens: pp.ParseResults) -> None: self.op = tokens[0][1] self.left = tokens[0][0] self.right = tokens[0][2] def __repr__(self) -> str: return f"BinaryOp({self.op}, {self.left}, {self.right})" and_ = pp.Keyword("AND") or_ = pp.Keyword("OR") word = (~(and_ | or_) + pp.Word(pp.alphanums + pp.alphas8bit + "_")).set_parse_action(Term) expression = pp.infix_notation( word, [ (pp.Optional(and_), 2, pp.opAssoc.LEFT, BinaryOp), (or_, 2, pp.opAssoc.LEFT, BinaryOp), ], ) input_string = "alpha OR beta gamma" parsed_result = expression.parseString(input_string) print(parsed_result.asList())
解决方案
问题核心是pp.Optional(and_)无法匹配无显式运算符的相邻术语,需要调整运算符定义,用pp.Empty()表示隐式AND,同时明确运算符优先级(AND优先级高于OR)。
修改后的代码:
import pyparsing as pp class Term: def __init__(self, tokens: pp.ParseResults): self.value = str(tokens[0]) def __repr__(self) -> str: return f"Term({self.value})" class BinaryOp: def __init__(self, tokens: pp.ParseResults) -> None: # 处理隐式AND:无显式运算符时默认设为"AND" tokens_list = tokens[0] if len(tokens_list) == 2: self.op = "AND" self.left = tokens_list[0] self.right = tokens_list[1] else: self.op = tokens_list[1] self.left = tokens_list[0] self.right = tokens_list[2] def __repr__(self) -> str: return f"BinaryOp({self.op}, {self.left}, {self.right})" and_ = pp.Keyword("AND") or_ = pp.Keyword("OR") word = (~(and_ | or_) + pp.Word(pp.alphanums + pp.alphas8bit + "_")).set_parse_action(Term) expression = pp.infix_notation( word, [ # 先处理显式AND和隐式AND(用pp.Empty()匹配无运算符的相邻术语) ((and_ | pp.Empty()), 2, pp.opAssoc.LEFT, BinaryOp), # OR优先级低于AND,后处理 (or_, 2, pp.opAssoc.LEFT, BinaryOp), ], ) input_string = "alpha OR beta gamma" parsed_result = expression.parseString(input_string) print(parsed_result.asList())
关键改动说明
- BinaryOp逻辑调整:增加对隐式AND的判断,当解析结果只有左右两个Term时,自动将运算符设为
AND; - 运算符优先级排序:将AND类运算符(显式+隐式)放在OR前面,符合布尔表达式的运算优先级规则;
- 隐式AND匹配:用
pp.Empty()匹配两个Term直接相连的场景,触发BinaryOp解析。
运行修改后的代码,输入alpha OR beta gamma的输出为:[BinaryOp(OR, Term(alpha), BinaryOp(AND, Term(beta), Term(gamma)))],完全符合预期。
内容的提问来源于stack exchange,提问作者medihack
相关产品推荐
相关产品推荐

