如何用Python解析SWMM模型.inp文件中特殊格式的表头?
解析SWMM .inp文件特殊格式表头的Python方案
我明白你在处理SWMM .inp文件时遇到的头疼问题——那些跨多行、没有固定分隔符的表头确实很难搞,只取最后一行肯定丢失了关键的分类信息。下面我给你一套完整的解决方案,利用SWMM表头的对齐特性(分隔线行)来精准解析完整表头,再提取对应的数据生成DataFrame。
核心思路
SWMM这类特殊表头的关键线索是分隔线行(全由短横线组成的行),它的每个短横线块的宽度正好对应每个表头列的宽度范围。我们可以:
- 先定位到目标数据块(SWMM的.inp文件用
[SectionName]分块) - 收集所有表头相关行(包括
;;开头的分类行、分隔线行) - 用分隔线行确定每个列的宽度边界
- 按边界提取每一行的表头内容,合并成完整列名
- 用同样的边界分割数据行,生成DataFrame
完整代码实现
import re import pandas as pd def parse_swmm_inp_table(inp_fname, section_name): # 读取文件并预处理:移除空行和首尾空白 with open(inp_fname, 'r') as f: lines = [line.strip() for line in f if line.strip()] # 定位目标数据块的起始位置 section_start = None for idx, line in enumerate(lines): if line.startswith(f'[{section_name}]'): section_start = idx + 1 break if not section_start: raise ValueError(f"找不到目标数据块 [{section_name}]") # 收集所有表头行:包括;;开头的说明行和分隔线行 header_lines = [] data_start_idx = section_start for idx in range(section_start, len(lines)): current_line = lines[idx] # 判断是否为表头行:要么是;;开头,要么是纯短横线+空格的分隔线 if current_line.startswith(';;') or re.fullmatch(r'[- ]+', current_line): header_lines.append(current_line) data_start_idx = idx + 1 else: # 遇到数据行或下一个数据块标记,停止收集表头 if current_line.startswith('['): break else: break # 提取分隔线行(用来确定列宽的关键) separator_line = None for line in header_lines: if re.fullmatch(r'-+', line.replace(' ', '')): separator_line = line break if not separator_line: raise ValueError("表头中未找到分隔线行,无法确定列宽") # 确定每个列的起始和结束索引(从分隔线行的短横线块位置提取) col_bounds = [(match.start(), match.end()) for match in re.finditer(r'-+', separator_line)] # 合并多行列内容,生成完整表头 column_headers = [] for start, end in col_bounds: header_parts = [] for line in header_lines: # 提取当前列区域的内容,清理多余符号和空格 part = line[start:end].strip().replace(';;', '').strip() if part: header_parts.append(part) # 合并同一列的多行内容 full_header = ' '.join(header_parts) column_headers.append(full_header) # 提取数据行:按列宽边界分割每行内容 data_rows = [] for idx in range(data_start_idx, len(lines)): current_line = lines[idx] if current_line.startswith('['): # 遇到下一个数据块,停止读取 break row_values = [] for start, end in col_bounds: val = current_line[start:end].strip() row_values.append(val) data_rows.append(row_values) # 生成DataFrame return pd.DataFrame(data_rows, columns=column_headers)
使用示例
假设你要解析的是.inp文件中的[TIMESERIES]块,只需调用:
# 替换为你的文件路径和目标数据块名称 df = parse_swmm_inp_table('your_swmm_model.inp', 'TIMESERIES') print(df.head())
关键优势
- 适配任意行数的表头:不管表头跨2行还是3行,都会自动合并对应列的所有内容
- 比空格分割更可靠:利用固定宽度分割,避免了数据中含单个空格导致的分割错误
- 精准定位数据块:通过SWMM的
[Section]标记定位,不会误读其他块的内容
内容的提问来源于stack exchange,提问作者Prasanna dahal
相关产品推荐
相关产品推荐

