Python如何将字符串列表解析为含numpy数组的字典
解析类MATPOWER case格式字符串为字典的通用方案
问题描述
现有如下格式的字符串列表,为类Matpower的电网算例配置文本:
['name = case1101', '', "version = '2';", '', 'alpha = [', '\t1\t3\t0\t0\t0\t0\t1\t1.06\t0\t0\t1\t1.06\t0.94;', '\t2\t2\t21.7\t12.7\t0\t0\t1\t1.045\t-4.98\t0\t1\t1.06\t0.94;', '];', '', 'beta = [', '\t1\t232.4\t-16.9\t10\t0\t1.06\t100\t1\t332.4\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0;', '\t2\t40\t42.4\t50\t-40\t1.045\t100\t1\t140\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0\t0;', '];', '', 'gamma = [', '\t1\t2\t0.01938\t0.05917\t0.0528\t0\t0\t0\t0\t0\t1\t-360\t360;', '\t1\t5\t0.05403\t0.22304\t0.0492\t0\t0\t0\t0\t0\t1\t-360\t360;', '\t2\t3\t0.04699\t0.19797\t0.0438\t0\t0\t0\t0\t0\t1\t-360\t360;', '];', '']
需要将其解析为如下结构的字典:其中标量字段直接提取字符串值,数组类字段(alpha、beta、gamma)转换为浮点数组成的numpy数组。
case = { "name": "case1101", "version": "2", "alpha": np.array([[1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.06, 0.0, 0.0, 1.0, 1.06, 0.94], ...]) }
原有实现为针对单个字段硬编码正则匹配+列表推导转浮点数,存在通用性差、正则容错性低的问题,需要更简洁优雅的通用实现。
原有实现代码参考:
lines = "\n".join(lines); search = re.search("alpha = \[([-\s0-9e.;]+)\]", lines).group(1); np.array([[float(v) for v in r.strip().split()] for r in s.strip(';\n\t ').split(';')]);
实现思路
采用逐行扫描的状态机逻辑替代硬编码正则,无需提前预知字段名称即可自动适配所有标量、数组配置项:
- 逐行遍历原始文本,跳过空行
- 识别到
key = [格式的行时,进入数组收集状态,缓存当前字段名 - 识别到
];格式的行时,结束数组收集,将缓存的数组内容交给numpy内置加载方法解析为浮点数组 - 非数组收集状态下,按
key = value格式解析标量字段,自动清洗值末尾的分号、包裹的引号 - 数组解析复用numpy原生的文本加载能力,自动处理制表符、分号、科学计数法、正负号等格式,无需手动编写数值转换逻辑
完整实现代码
import numpy as np from io import StringIO def parse_case(raw_lines): case_dict = {} current_arr_key = None arr_buffer = [] for line in raw_lines: stripped = line.strip() # 跳过空行 if not stripped: continue # 匹配数组起始标记 if stripped.endswith("= ["): current_arr_key = stripped.split("=", 1)[0].strip() arr_buffer = [] continue # 匹配数组结束标记,解析缓存的数组内容 if stripped == "];": # 替换行尾分号,拼接为符合numpy加载格式的文本 arr_text = "\n".join(arr_buffer).replace(";", "") case_dict[current_arr_key] = np.loadtxt(StringIO(arr_text), dtype=np.float64) current_arr_key = None continue # 数组收集阶段,直接缓存当前行 if current_arr_key is not None: arr_buffer.append(stripped) continue # 解析普通标量键值对 key, value = [part.strip() for part in stripped.split("=", 1)] # 移除末尾分号 value = value.rstrip(";") # 移除包裹的单/双引号 if (value.startswith("'") and value.endswith("'")) or (value.startswith('"') and value.endswith('"')): value = value[1:-1] case_dict[key] = value return case_dict
调用方式:
case = parse_case(raw_lines)
方案优势
- 通用性强:无需提前枚举字段名,后续新增任意标量、数组配置项都可自动解析,无需修改解析逻辑
- 鲁棒性高:自动兼容空格/制表符缩进、行尾多余空格、科学计数法数值、带正负号数值等格式变体,不存在正则漏匹配问题
- 性能更好:数组解析复用numpy原生C实现的文本加载逻辑,比纯Python列表推导循环转浮点数速度更快,解析大体积数组时优势明显
- 可维护性高:逻辑为线性逐行处理,无复杂正则表达式,代码可读性远高于硬编码正则方案
内容的提问来源于stack exchange,提问作者fourloops
相关产品推荐
相关产品推荐

