You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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)

关键调整说明

  1. 解决as_dict()覆盖问题
    所有需要收集多个实例的节点(平台、命令、任务),都在setResultsName里加上listAllMatches=True,这样pyparsing会把所有匹配结果收集成列表,而不是用最后一个结果覆盖之前的。

  2. 统一任务格式
    针对三种任务格式(简单别名、带属性块、显式alias定义),通过setParseAction统一转换成{"alias": ...}的字典结构,确保输出符合预期格式。

  3. 保证顺序一致性
    使用delimitedList配合listAllMatches=True,解析结果会严格保留输入中的顺序,最终的平台列表、命令列表、任务列表都是有序的。

  4. 简化语法定义
    用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:45:23