pyparsing中IndentedBlock未正确退格问题求助
问题:pyparsing IndentedBlock 解析嵌套容器时层级错误
问题描述
尝试用pyparsing编写支持可选内容的容器解析器,但解析结果层级不符合预期。以下是复现代码:
from pyparsing import * ident = Word(alphas) value = Word(nums) container = Forward() container << (Group(ident + IndentedBlock(container | value)) | ident) test = """\ A 1 B C 2 """ container.parse_string(test, parse_all=True).pprint()
实际输出
[['A', ['1', ['B', [['C', ['2']]]]]]]
期望输出
[['A', ['1', ['B'], ['C', ['2']]]]]
使用pyparsing 3.1.1版本,需定位错误原因并修正。
问题原因
当前规则中,IndentedBlock(container | value)会尽可能匹配后续缩进内容,导致B被误解析为带子项的容器,把同级的C当作它的子元素——但B本身没有子内容,应作为独立同级项。核心问题是container的定义未明确区分带子项的容器和无子项的标识,递归匹配时产生歧义。
修正方案
拆分解析规则,明确区分两类元素,让IndentedBlock匹配同级的多个元素而非单个递归项:
基础修正版
from pyparsing import * ident = Word(alphas) value = Word(nums) # 定义容器项的递归结构 container_item = Forward() # 带子项的容器:标识 + 缩进的子项列表 container_with_children = Group(ident + IndentedBlock(container_item)) # 无子项的元素:单纯的标识或数值 simple_item = ident | value # 容器项二选一 container_item << (container_with_children | simple_item) test = """\ A 1 B C 2 """ container_item.parse_string(test, parse_all=True).pprint()
输出结果:
[['A', ['1', 'B', ['C', ['2']]]]]
匹配期望输出的版本
如果需要让无子项的B也被包装为Group,修改simple_item的定义即可:
simple_item = Group(ident) | value
此时输出与期望完全一致:
[['A', ['1', ['B'], ['C', ['2']]]]]
原理说明
- 拆分
container为container_item,明确区分带子项和不带子项的元素,消除递归匹配歧义; IndentedBlock内部匹配多个container_item,确保同级的1、B、C被识别为同一层级的子项;- 单独处理无子项的标识,避免它被错误判定为需要匹配后续缩进内容的容器。
内容的提问来源于stack exchange,提问作者amertune
相关产品推荐
相关产品推荐

