如何用Lark递归读取多个include引用的配置文件?
解决Lark解析配置文件时的目录Include合并问题
问题背景
现有自定义格式的配置文件,其中include语句指向目录时,需要读取该目录下所有.conf文件,并将解析后的内容合并到原语法树中。已完成Lark语法规则编写,且能通过Transformer获取到include指定的目录路径,但不清楚如何合并解析后的子文件内容到原树。
解决方案
核心思路是在Transformer的include处理方法中,遍历目标目录下的所有.conf文件,逐一解析后提取其语法树的根节点子元素,替换原include节点:
- 导入
os模块处理目录遍历与路径拼接 - 在Transformer中复用已创建的Lark解析器实例,避免重复初始化开销
- 遍历目标目录下所有
.conf文件,按文件名排序保证解析顺序稳定 - 提取每个子文件语法树中
start节点的所有子元素,合并后返回替换原include节点
修改后的完整代码
Transformer与解析逻辑
#!/usr/bin/env python3 from lark import Lark, Transformer, Tree from pprint import pprint import os class ExpandIncludes(Transformer): def __init__(self, parser, base_dir): self.parser = parser self.base_dir = base_dir # 主配置文件所在目录,用于处理相对路径 def include(self, item): path = item[0] dir_path = strip_quotes(path.children[0].value) # 处理相对路径:基于主配置文件所在目录拼接 full_dir = os.path.join(self.base_dir, dir_path) included_nodes = [] # 遍历目录下所有.conf文件,按文件名排序保证顺序稳定 for filename in sorted(os.listdir(full_dir)): if filename.endswith('.conf'): file_path = os.path.join(full_dir, filename) with open(file_path, 'r') as f: content = f.read() # 解析子文件语法树 sub_tree = self.parser.parse(content) # 提取start节点下的所有子元素(value或COMMENT) included_nodes.extend(sub_tree.children) # 返回合并后的节点列表,替换原include节点 return included_nodes def strip_quotes(s): if s.startswith('"') and s.endswith('"'): return s[1:-1] def parse_file(conf_grammar, conf_file): # 创建解析器实例,复用给Transformer避免重复初始化 conf_parser = Lark(conf_grammar, parser='earley') # 获取主配置文件所在目录,用于处理相对路径 base_dir = os.path.dirname(os.path.abspath(conf_file)) with open(conf_file, 'r') as f: test_conf = f.read() tree = conf_parser.parse(test_conf) # 初始化Transformer时传入解析器和基础目录 tree = ExpandIncludes(conf_parser, base_dir).transform(tree) return tree if __name__ == '__main__': with open('parseconf/try.lark') as f: conf_grammar = f.read() tree = parse_file(conf_grammar, 'parseconf/test.conf') print(tree.pretty())
关键修改说明
- Transformer初始化:新增
parser和base_dir参数,复用解析器降低开销,同时解决相对路径解析问题 - 目录遍历:过滤
.conf文件并按文件名排序,保证解析顺序可预测 - 节点合并:将子文件语法树的
start子节点全部提取合并,原include节点会被这些节点替代 - 路径处理:通过
os.path.join拼接主配置目录与include路径,确保相对路径正确解析
验证效果
运行修改后的代码,原配置中的include "parseconf/dir_with_many_files"节点会被替换为该目录下所有.conf文件解析后的语法树节点,最终输出的语法树会包含所有合并后的内容。
内容的提问来源于stack exchange,提问作者tuck1s
相关产品推荐
相关产品推荐

