如何判断pyparsing中ParseResults对应的ParserElement来源?
解决方案:给pyparsing Group的ParseResults标记原始表达式
方案一:给ParseResults添加自定义标记属性(最简单)
不用自定义子类,直接给每个Group的ParseResults加属性标记对应的生成表达式,避免子类初始化的麻烦:
- 定义通用的parse action生成函数,用来给结果打标记:
from pyparsing import * def mark_parser_type(parser_identifier): def parse_action(s, loc, tokens): # 给ParseResults添加自定义属性,标记对应的ParserElement或标识名 tokens._parser_type = parser_identifier return tokens return parse_action
- 给每个Group绑定这个parse action,传入对应的标识(可以是字符串,也可以直接传入ParserElement对象):
# 定义带标记的Group first_and_operator = Group(Char('ab')('first') + Char('+-')('operator')).add_parse_action(mark_parser_type("first_and_operator")) full_expression = Group(first_and_operator + Char('cd')('second')).add_parse_action(mark_parser_type("full_expression")) # 测试解析 result = full_expression.parse_string('a+d', parse_all=True) print(result[0]._parser_type) # 输出:full_expression print(result[0][0]._parser_type) # 输出:first_and_operator
如果要更精确关联原始ParserElement,直接传对象即可:
first_and_operator = Group(Char('ab')('first') + Char('+-')('operator')) first_and_operator.add_parse_action(mark_parser_type(first_and_operator)) # 后续可直接判断身份 if result[0][0]._parser_type is first_and_operator: print("这是first_and_operator生成的结果")
方案二:正确实现自定义TypedParseResults子类
如果一定要用自定义子类,需要修正初始化逻辑,兼容pyparsing的调用方式:
- 定义正确的子类,兼容父类初始化参数:
class TypedParseResults(ParseResults): def __init__(self, *args, result_type=None, **kwargs): # 先调用父类初始化 super().__init__(*args, **kwargs) # 设置自定义类型标记 self.result_type = result_type
- 编写转换用的parse action函数:
def convert_to_typed(result_type): def parse_action(s, loc, tokens): # 将原始ParseResults转换为自定义子类实例 typed_result = TypedParseResults(tokens, result_type=result_type) # 复制所有命名结果(确保原有属性不丢失) for name, value in tokens.named_items(): typed_result[name] = value return typed_result return parse_action
- 给Group绑定这个parse action:
first_and_operator = Group(Char('ab')('first') + Char('+-')('operator')).add_parse_action(convert_to_typed("first_and_operator")) full_expression = Group(first_and_operator + Char('cd')('second')).add_parse_action(convert_to_typed("full_expression")) # 测试解析 result = full_expression.parse_string('a+d', parse_all=True) print(isinstance(result[0], TypedParseResults)) # 输出:True print(result[0].result_type) # 输出:full_expression
关键说明
- 两种方案都支持CST和AST解析器独立配置:同一个Group可以在CST解析器中绑定一种标记,在AST解析器中绑定另一种,互不影响。
- 不会和自定义Expand类冲突:parse action仅对解析结果进行标记/转换,不影响原有语法结构和Expand逻辑。
- 扩展性强:新增Group时只需添加对应的parse action,无需修改现有代码。
内容的提问来源于stack exchange,提问作者InSync
相关产品推荐
相关产品推荐

