如何用pyparsing将类命令字符串解析为指定格式的字典列表
使用pyparsing解析类命令格式字符串为指定字典结构
问题背景
给定输入字符串:
input_str = "p1 start a, {alias = b, for : 30}; c, d stop e"
需要解析成如下指定格式的字典:
{ "platforms": [ { "platform": "p1", "commands": [ { "cmd": "start", "tasks": [ {"alias": "a"}, {"alias": "b", "for": "30"}, {"alias": "c"}, {"alias": "d"} ] }, { "cmd": "stop", "tasks": [{"alias": "e"}] } ] } ] }
遇到的问题:
- 初始解析代码输出格式不符合预期
- 多平台输入时,
res.as_list()能拿到所有令牌,但res.as_dict()只返回最后一个平台的数据 - 需要输出有序的字典列表来保证处理顺序
解决代码
from pyparsing import ( Word, alphas, alphanums, Suppress, delimitedList, Group, Dict, Optional, ParserElement ) # 全局配置:允许空白符作为分隔 ParserElement.setDefaultWhitespaceChars(" \t\n") # 定义基础语法单元 identifier = Word(alphas, alphanums + "_") # 匹配平台名、命令、属性名 eq_or_colon = Suppress(Optional("=") | ":") # 忽略等号或冒号 value = Word(alphanums) # 匹配属性值或简单别名 # 解析带属性的任务块:{alias = b, for : 30} task_attrs = Dict(Group(identifier + eq_or_colon + value)) bracketed_task = Suppress("{") + task_attrs + Suppress("}") # 解析单个任务:兼容三种格式,统一转为字典结构 def simple_alias_parse_action(s, l, t): return {"alias": t[0]} task = (bracketed_task | Group(identifier.setParseAction(simple_alias_parse_action)) | Group(Word("alias") + eq_or_colon + identifier).setParseAction(lambda s,l,t: {"alias": t[2]})) # 解析命令:命令名 + 逗号分隔的任务列表 command = Group( identifier.setResultsName("cmd") + delimitedList(task).setResultsName("tasks", listAllMatches=True) ) # 解析平台块:平台名 + 分号分隔的命令列表 platform_block = Group( identifier.setResultsName("platform") + delimitedList(command, ";").setResultsName("commands", listAllMatches=True) ) # 完整表达式:支持多个平台块(逗号分隔) expr = delimitedList(platform_block).setResultsName("platforms", listAllMatches=True) # 测试解析 input_str = "p1 start a, {alias = b, for : 30}; c, d stop e" result = expr.parseString(input_str) output = result.asDict() print(output)
关键调整说明
解决
as_dict()覆盖问题
所有需要收集多个实例的节点(平台、命令、任务),都在setResultsName里加上listAllMatches=True,这样pyparsing会把所有匹配结果收集成列表,而不是用最后一个结果覆盖之前的。统一任务格式
针对三种任务格式(简单别名、带属性块、显式alias定义),通过setParseAction统一转换成{"alias": ...}的字典结构,确保输出符合预期格式。保证顺序一致性
使用delimitedList配合listAllMatches=True,解析结果会严格保留输入中的顺序,最终的平台列表、命令列表、任务列表都是有序的。简化语法定义
用Suppress忽略不需要的分隔符(括号、等号、冒号),用delimitedList处理逗号/分号分隔的元素,让语法规则更简洁易懂。
多平台测试示例
如果输入多平台字符串:
multi_input = "p1 start a, b; stop c; p2 start d, {alias=e, for:60}" result = expr.parseString(multi_input) print(result.asDict())
输出会包含两个平台的数据,顺序和输入一致:
{ 'platforms': [ { 'platform': 'p1', 'commands': [ {'cmd': 'start', 'tasks': [{'alias': 'a'}, {'alias': 'b'}]}, {'cmd': 'stop', 'tasks': [{'alias': 'c'}]} ] }, { 'platform': 'p2', 'commands': [ {'cmd': 'start', 'tasks': [{'alias': 'd'}, {'alias': 'e', 'for': '60'}]} ] } ] }
内容的提问来源于stack exchange,提问作者DZkid
相关产品推荐
相关产品推荐

