Python解析Arbin测试调度格式:工具选型与实现咨询
解析Arbin测试调度格式的Python方案需求
需要解析一种无文档的Arbin测试调度格式,该格式类似TOML但字符串无需引号,示例输入如下:
[Schedule_Step122] m_nMaxCurrent=0 m_szAddIn=Relay OFF m_szLabel=06 - End Charge m_uLimitNum=2 [Schedule_Step122_Limit0] Equation0_szCompareSign=>= Equation0_szRight=F_05_Charge_Capacity Equation0_szLeft=PV_CHAN_Charge_Capacity m_bStepLimit=1 m_szGotoStep=End Test [Schedule_Step122_Limit1] Equation0_szCompareSign=>= Equation0_szLeft=PV_CHAN_Voltage Equation0_szRight=3 m_bStepLimit=1 m_szGotoStep=End Test
期望解析后生成结构化数据(示例JSON):
{ "steps": [ { "max_current": 0, "add_in": "RELAY_OFF", "label": "09 - End Charge", "limits": [ { "equations": [ { "left": "PV_CHAN_CHARGE_CAPACITY", "compare_sign": ">=", "right": "F_05_CHARGE_CAPACITY" } ], "step_limit": 1, "goto_step": "END_TEST" }, { "equations": [ { "left": "PV_CHAN_VOLTAGE", "compare_sign": ">=", "right": 6 } ], "step_limit": 1, "goto_step": "END_TEST" } ] } ] }
核心挑战:
- 字符串无需引号,需自定义值的解析逻辑
- 部分值需要转换为大写命名常量
- 处理嵌套关联:
Schedule_StepXXX_LimitYY隶属于对应的Schedule_StepXXX - 键的无序性不影响解析结果
纠结点:选择通用解析工具(ANTLR/PLY/pyparsing/Lark)还是编写自定义解析逻辑?
推荐方案
优先用pyparsing或Lark实现,比自定义解析更可靠
这类类INI格式的解析,用pyparsing或者Lark这类声明式解析工具更高效,也更容易维护,尤其是后续格式有小变化时,修改规则比改自定义正则/逐行逻辑简单。
关键实现思路
- 解析Section结构:先定义
[SectionName]的语法规则,提取Section名称后,用正则(如r"Schedule_Step(\d+)(?:_Limit(\d+))?")拆分出step编号和limit编号,以此建立父子关联。 - 解析键值对:定义
Key=Value规则,其中Value支持数字、带空格的无引号字符串;针对不同Key设置类型转换(如整数转int、指定字符串转大写常量)。 - 构建结构化数据:用字典存储所有step,解析到Limit类型的Section时,根据step编号找到对应父step,将Limit数据添加到父step的
limits列表,最后整理为目标结构。
pyparsing示例片段
from pyparsing import ( Word, nums, alphas, alphanums, Suppress, Group, Dict, OneOrMore, Regex ) import re # 定义语法规则 section_start = Suppress("[") section_end = Suppress("]") section_name = Word(alphanums + "_") key = Word(alphanums + "_") # 匹配无引号值:排除[]和换行,自动去首尾空格 value = Regex(r"[^[\]\n]+").setParseAction(lambda s: s[0].strip()) integer_value = Word(nums).setParseAction(lambda s: int(s[0])) key_value_pair = Group(key + Suppress("=") + (integer_value | value)) section = Group(section_start + section_name + section_end + OneOrMore(key_value_pair)) # 解析文件 parser = OneOrMore(section) parsed_data = parser.parse_file("arbin_schedule.txt") # 构建目标结构 steps = {} step_pattern = re.compile(r"Schedule_Step(\d+)") limit_pattern = re.compile(r"Schedule_Step(\d+)_Limit(\d+)") for sec in parsed_data: sec_name = sec[0] kv_dict = dict(sec[1:]) limit_match = limit_pattern.match(sec_name) if limit_match: step_id = limit_match.group(1) # 处理Equation eq_left = kv_dict["Equation0_szLeft"].upper() eq_sign = kv_dict["Equation0_szCompareSign"] eq_right = kv_dict["Equation0_szRight"] eq_right = eq_right.upper() if not eq_right.isdigit() else int(eq_right) limit_item = { "equations": [{"left": eq_left, "compare_sign": eq_sign, "right": eq_right}], "step_limit": int(kv_dict["m_bStepLimit"]), "goto_step": kv_dict["m_szGotoStep"].upper().replace(" ", "_") } steps[step_id]["limits"].append(limit_item) continue step_match = step_pattern.match(sec_name) if step_match: step_id = step_match.group(1) steps[step_id] = { "max_current": int(kv_dict["m_nMaxCurrent"]), "add_in": kv_dict["m_szAddIn"].upper().replace(" ", "_"), "label": kv_dict["m_szLabel"], "limits": [] } # 转换为最终格式 result = {"steps": list(steps.values())} print(result)
自定义解析的适用场景
如果格式非常简单且短期内不会变化,也可以写自定义逐行解析:
- 逐行读取文件,跳过空行
- 遇到
[开头的行,解析Section名称并判断类型(Step/Limit) - 普通行解析键值对,根据当前Section类型存储数据
- 通过Section名称的命名规则关联父子结构
但自定义解析容易在边缘情况(如值含特殊符号、多行值)出错,不如工具方案健壮。
内容的提问来源于stack exchange,提问作者markfickett
相关产品推荐
相关产品推荐

