使用Python从具有独特头打印技术的文件中解析头字符串(.inp扩展名)

2024-04-24 05:48:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望使用Python来解析文件中的数据帧(对于那些可能使用过它的SWMM模型input/inp文件的人)。文件头以一种非常独特的方式打印,这使得完全解析它变得非常困难。我试图从文件中读取的数据帧的示例是:

;;                                                 Param    
;;Node           Parameter        Time Series      Type     
;;-------------- ---------------- ---------------- -------- 
80408            FLOW             80408            FLOW     
81009            FLOW             81009            FLOW     
82309            FLOW             82309            FLOW     

标题没有用制表符或任何固定数量的空格分隔。另外,对于某些页眉,当它们的长度太大时,它们会占用两条垂直线,而其他标头只使用一条直线。宽度也不是固定的,有不止一个这样的数据帧,它们的宽度都不同。在

我所能做的就是抓住最下面的那条线作为头球。在

^{pr2}$

Tags: 文件数据模型node示例input宽度parameter
2条回答

由于您的数据不适合read_fwf中的插值,所以您可以自己扫描和解析头。一旦计算出列名和列宽,就可以将列名和列宽传递给read_fwf,文件指针在第一行打开。页眉和数据之间的虚线分隔符是列宽的一个很好的指示器,所以我用它来计算列宽。在

import pandas as pd
import re

# write a test file...
open('test.txt', 'w').write("""\
;;                                                 Param    
;;Node           Parameter        Time Series      Type     
;;                               
80408            FLOW             80408            FLOW     
81009            FLOW             81009            FLOW     
82309            FLOW             82309            FLOW     """)


def make_dataframe(filename):
    with open('test.txt') as fp:
        # grab header
        headers = []
        for line in fp:
            if not line.startswith(';;-'):
                # header line, swap '  ' for ';;' to maintain len
                headers.append('  ' + line[2:-1])
            else:
                break
        else:
            print("ERROR: Header separator not found")
            return None

        # end of header, convert '  ' separators to field lengths
        field_lens = [len(m)+1 for m in re.findall(r"\-+", ' ' + line[2:-1])]

        # flatten multiline column names
        start = 0
        pd_header = []
        for f_len in field_lens:
            pd_header.append(' '.join(field.strip()
                for field in (h[start:start+f_len] for h in headers)
                if field.strip()))
            start += f_len

        # read fix length columns
        df = pd.read_fwf(fp, header=None, names=pd_header, widths=field_lens,
            index_col=False)
        return df

df = make_dataframe('test.txt')
print(df)

与@tdelaney的代码相同的思想使其更加简洁:

from itertools import takewhile
import re
import pandas as pd

def make_dataframe(filename):
    with open(filename) as fp:
        div = []
        headers = list(takewhile(
            lambda x: not x.startswith(';;-') or div.append(x), fp))
        colspecs = [m.span() for m in re.compile("-+").finditer(div[0])]
        headers = [
            re.sub(" +", " ", " ".join(hl[lo : hi] for hl in headers)).strip()
            for lo, hi in colspecs]
        d = pd.read_fwf(fp, header = None,
            colspecs = [(lo - 2, hi - 2) for lo, hi in colspecs])
    d.columns = headers
    return d

print(make_dataframe('test.txt'))

相关问题 更多 >