分层解析比单次正则更可靠,因其通过粗粒度切分(如按行/段落)→分块适配策略(partition/ast/状态机)→语义感知选型(ast.parse优于硬塞正则)→错误恢复机制(strict=false、跳过坏行),实现鲁棒性。

分层解析为什么比单次正则更可靠
因为真实文本里嵌套结构、上下文依赖和边界模糊是常态,re.findall 一把梭容易漏匹配、错切分、或把注释当代码。比如解析带缩进的配置块+内联注释+跨行字符串,单层正则根本没法区分“#”是注释开始还是字符串内容。
- 先按行/段落做粗粒度切分(如用
str.splitlines()或re.split(r'\n\s*\n', text)分逻辑块) - 再对每个块选合适方式:纯键值用
str.partition(':'),带嵌套用ast.literal_eval或自定义状态机,含语法糖的才上re - 关键不是“能不能用正则”,而是“这一层是否需要理解语义”——需要就别硬塞正则
用 ast.parse 解析类 Python 结构最省心
如果你的文本长得像 Python(字典、列表、布尔、数字、字符串),直接喂给 ast.parse,它比手写状态机稳得多,还能自动处理引号转义、跨行字符串、注释忽略(只要不干扰语法)。
- 必须加
mode='eval'才能解析单个表达式,否则报SyntaxError: invalid syntax -
ast.literal_eval更安全但只支持字面量,遇到变量名或函数调用会直接抛ValueError - 想保留原始缩进或注释?不行。
ast只管语法结构,源码信息得靠ast.get_source_segment或提前存行号
状态机比递归下降更适合控制解析深度
当你要解析 YAML 风格缩进块、INI 的 section 嵌套、或自定义 DSL 的层级缩进时,递归函数容易栈溢出或逻辑缠绕;一个带 current_indent 和 stack 的简单状态机反而清晰可控。
- 每行开头空格数决定当前层级,比
re.match(r'(\s*)(\w+):')提取缩进再比大小更准 - 用列表模拟栈:
stack = [{'level': 0, 'type': 'root'}],新行 level > 栈顶就 push,小于就 pop 到匹配为止 - 别在状态机里做复杂转换——解析归解析,转换归转换,两步分开,出问题好定位
错误恢复比完美解析更重要
生产环境的文本总有缺括号、少引号、编码错乱,死在第一处错误等于放弃整片数据。与其卡住,不如记录 ParseError 位置,跳过坏行继续往下扫。
立即学习“Python免费学习笔记(深入)”;
- 用
try/except SyntaxError包ast.literal_eval,捕获后记日志并返回None或默认值 - 正则匹配失败时,别直接
raise,先检查是否是空行、注释行、或已知脏数据前缀(如'TODO:') - 所有分层入口函数都加
strict=False参数开关,默认容忍,调试时打开
真正难的不是写出能跑通的解析器,是让解析器在 70% 的脏数据里稳定吐出 95% 的有效字段——这靠的是分层隔离、错误隔离、和每一层都留退路。










