pyparsing使用infixNotation时如何将条件间空白识别为隐式AND运算符
你当前代码的核心问题在于pyparsing默认会自动跳过输入中的所有空白字符,所以你将空格加入AND的可选值是无效的,空白不会被当作有效token进入解析流程,解析器识别完第一个括号表达式后没有找到显式运算符,就会直接停止解析,忽略后续内容。
解决方法
- 拆分显式AND和隐式AND的定义,隐式AND使用
Empty()实现,不需要匹配任何实际字符,仅匹配两个表达式相邻的位置 - 调整运算符优先级:按
NOT > 隐式AND > 显式AND > OR的顺序配置,符合搜索语法的常规逻辑 - 隐式AND的解析结果和显式AND对齐,方便后续统一处理
修改后的完整代码如下:
import pyparsing as pp from pyparsing import Word, alphanums, Empty, oneOf field_name = Word(alphanums).setResultsName('field_name') search_value = Word(alphanums + '-').setResultsName('search_value') operator = pp.Literal(':') query = field_name + operator + search_value # 拆分显式AND和隐式AND EXPLICIT_AND = oneOf(['AND', 'and', '&']) # 隐式AND不匹配任何实际字符,解析后统一返回&,和显式AND对齐 IMPLICIT_AND = Empty().setParseAction(lambda: "&") OR = oneOf(['OR', 'or', '|']) NOT = oneOf(['NOT', 'not', '!']) query_expr = pp.infixNotation(query, [ (NOT, 1, pp.opAssoc.RIGHT, ), (IMPLICIT_AND, 2, pp.opAssoc.LEFT, ), # 隐式AND优先级高于显式AND (EXPLICIT_AND, 2, pp.opAssoc.LEFT, ), (OR, 2, pp.opAssoc.LEFT, ), ]) class ComparisonExpr: def __init__(self, tokens): self.tokens = tokens def __str__(self): return "Comparison:('field': {!r}, 'operator': {!r}, 'value': {!r})".format(*self.tokens) def __repr__(self): return self.__str__() query.addParseAction(ComparisonExpr) # 测试无显式运算符的样本 sample = "(field1:value1a | field1:value1b) (field2:value2a | field2:value2b)" result = query_expr.parseString(sample).asList() from pprint import pprint pprint(result)
运行输出结果符合预期:
[[[Comparison:('field': 'field1', 'operator': ':', 'value': 'value1a'), '|', Comparison:('field': 'field1', 'operator': ':', 'value': 'value1b')], '&', [Comparison:('field': 'field2', 'operator': ':', 'value': 'value2a'), '|', Comparison:('field': 'field2', 'operator': ':', 'value': 'value2b')]]]
如果需要隐式AND和显式AND优先级相同,可以将两者合并到同一个优先级组:
query_expr = pp.infixNotation(query, [ (NOT, 1, pp.opAssoc.RIGHT, ), ((EXPLICIT_AND | IMPLICIT_AND), 2, pp.opAssoc.LEFT, ), (OR, 2, pp.opAssoc.LEFT, ), ])
内容的提问来源于stack exchange,提问作者Nathan Jones
相关产品推荐
相关产品推荐

