解析非固定分隔符Fortran输出文件为指定4维矩阵的方法
Fortran无分隔符系数表读取方案
核心问题出在按空格split的思路完全依赖分隔符规范,而这类老Fortran程序的输出为了对齐字段经常会省略负数前的空格,直接按字符位置写数,所以必须换不依赖分隔符的提取逻辑。
核心思路
- 放弃按行读取、按空格分割的处理方式,直接对全量文本做模式匹配提取数值,完全绕开分隔符不固定的问题。
- Fortran输出的科学计数法格式非常固定:
[正负号]数字.数字E[正负号]数字,用正则[+-]?\d+\.\d+E[+-]\d+可以精准识别每一个数值,哪怕两个数粘在一起(比如2.452E-07-8.040E-07),也能正确切分成两个独立值,不会把第二个数的负号当成前一个数的一部分。 - 按固定层级切分文本,逐段提取后组装成目标维度的矩阵:
- 第一层:匹配所有带
CLIMATOLOGY :的表头,把全文件切成4段对应4张系数表 - 第二层:在每张表内匹配固定的3位月份缩写(JAN到DEC),切分12个月份块
- 第三层:在每个月份块内匹配-85到85的纬度标识,切分18个纬度条目
- 第四层:每个纬度条目内用正则提取25个数值,转成浮点型存入矩阵对应位置
- 第一层:匹配所有带
参考实现代码
import re import numpy as np # 固定配置项 TABLE_NUM = 4 MONTH_NUM = 12 LAT_NUM = 18 LEVEL_NUM = 25 LAT_VALUES = [-85, -75, -65, -55, -45, -35, -25, -15, -5, 5, 15, 25, 35, 45, 55, 65, 75, 85] MONTH_VALUES = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"] # 预编译正则提升效率 NUM_PATTERN = re.compile(r'[+-]?\d+\.\d+E[+-]\d+') TABLE_HEAD_PATTERN = re.compile(r'.*CLIMATOLOGY :.*') ENTRY_HEAD_PATTERN = re.compile(r'(' + '|'.join(MONTH_VALUES) + r')\s+(-?\d+)\s+\S+\s+cli\s+') # 读入完整文件 with open("你的输入文件路径", "r", encoding="utf-8") as f: full_content = f.read() # 初始化目标4维矩阵 TAB = np.zeros((TABLE_NUM, MONTH_NUM, LAT_NUM, LEVEL_NUM), dtype=np.float64) # 逐表处理 table_pos = list(TABLE_HEAD_PATTERN.finditer(full_content)) for t_idx in range(TABLE_NUM): t_start = table_pos[t_idx].end() t_end = table_pos[t_idx+1].start() if t_idx < TABLE_NUM -1 else len(full_content) t_content = full_content[t_start:t_end] # 逐纬度条目处理 entry_pos = list(ENTRY_HEAD_PATTERN.finditer(t_content)) for e_idx, entry in enumerate(entry_pos): month_abbr, lat_val = entry.groups() m_idx = MONTH_VALUES.index(month_abbr) lat_idx = LAT_VALUES.index(int(lat_val)) e_start = entry.end() e_end = entry_pos[e_idx+1].start() if e_idx < len(entry_pos)-1 else len(t_content) e_content = t_content[e_start:e_end] # 提取数值并做数量校验 values = [float(v) for v in NUM_PATTERN.findall(e_content)] if len(values) != LEVEL_NUM: raise ValueError(f"表{t_idx} {month_abbr} 纬度{lat_val} 提取数值异常,预期{LEVEL_NUM}个,实际{len(values)}个") TAB[t_idx, m_idx, lat_idx, :] = values
补充说明
- 这套逻辑完全不关心换行、空格的位置,只要数值本身是标准Fortran科学计数法格式,哪怕多个数完全粘连也能正确拆分,适配样例里的负号粘连场景。
- 代码里加了数值长度校验,如果某段提取的数值数量不对会直接抛出异常标注位置,方便排查文件里的特殊格式问题。如果文件里存在小写e表示指数、或者整数格式的数值,只要微调
NUM_PATTERN的匹配规则即可,核心处理逻辑不需要改动。
内容的提问来源于stack exchange,提问作者KuKaKi
相关产品推荐
相关产品推荐

