从文本文件中解析数据

时间:2013-06-14 09:35:11

标签: python file parsing

我有一个包含以下内容的文本文件:

******** ENTRY 01 ********
ID:                  01
Data1:               0.1834869385E-002
Data2:              10.9598489301
Data3:              -0.1091356549E+001
Data4:                715

然后是一个空行,并重复更多类似的块,所有这些块都具有相同的数据字段。

我正在向Python移植一个​​C ++代码,某个部分逐行获取文件,检测文本标题,然后检测每个字段文本以提取数据。这看起来并不像一个智能代码,我认为Python必须有一些库来轻松地解析这样的数据。毕竟,它几乎看起来像一个CSV!

对此有何想法?

3 个答案:

答案 0 :(得分:9)

实际上离CSV非常远。

您可以将该文件用作迭代器;以下生成器函数生成完整的部分:

def load_sections(filename):
    with open(filename, 'r') as infile:
        line = ''
        while True:
            while not line.startswith('****'): 
                line = next(infile)  # raises StopIteration, ending the generator
                continue  # find next entry

            entry = {}
            for line in infile:
                line = line.strip()
                if not line: break

                key, value = map(str.strip, line.split(':', 1))
                entry[key] = value

            yield entry

这会将文件视为迭代器,这意味着任何循环都会将文件前进到下一行。外环仅用于从一个部分移动到另一个部分;内部whilefor循环完成所有实际工作;首先跳过行,直到找到****标题部分(否则丢弃),然后遍历所有非空行以创建一个部分。

在循环中使用该功能:

for section in load_sections(filename):
    print section

在文本文件中重复样本数据会导致:

>>> for section in load_sections('/tmp/test.txt'):
...     print section
... 
{'Data4': '715', 'Data1': '0.1834869385E-002', 'ID': '01', 'Data3': '-0.1091356549E+001', 'Data2': '10.9598489301'}
{'Data4': '715', 'Data1': '0.1834869385E-002', 'ID': '01', 'Data3': '-0.1091356549E+001', 'Data2': '10.9598489301'}
{'Data4': '715', 'Data1': '0.1834869385E-002', 'ID': '01', 'Data3': '-0.1091356549E+001', 'Data2': '10.9598489301'}

如果您愿意,可以添加一些数据转换器;密钥到可调用的映射可以:

converters = {'ID': int, 'Data1': float, 'Data2': float, 'Data3': float, 'Data4': int}

然后在生成器函数中,而不是entry[key] = value执行entry[key] = converters.get(key, lambda v: v)(value)

答案 1 :(得分:4)

my_file:

******** ENTRY 01 ********
ID:                  01
Data1:               0.1834869385E-002
Data2:              10.9598489301
Data3:              -0.1091356549E+001
Data4:                715

ID:                  02
Data1:               0.18348674325E-012
Data2:              10.9598489301
Data3:              0.0
Data4:                5748

ID:                  03
Data1:               20.1834869385E-002
Data2:              10.954576354
Data3:              10.13476858762435E+001
Data4:                7456

Python脚本:

import re

with open('my_file', 'r') as f:
    data  = list()
    group = dict()
    for key, value in re.findall(r'(.*):\s*([\dE+-.]+)', f.read()):
        if key in group:
            data.append(group)
            group = dict()
        group[key] = value
    data.append(group)

print data

印刷输出:

[
    {
        'Data4': '715',
        'Data1': '0.1834869385E-002',
        'ID': '01',
        'Data3': '-0.1091356549E+001',
        'Data2': '10.9598489301'
    },
    {
        'Data4': '5748',
        'Data1': '0.18348674325E-012',
        'ID': '02',
        'Data3': '0.0',
        'Data2': '10.9598489301'
    },
    {
        'Data4': '7456',
        'Data1': '20.1834869385E-002',
        'ID': '03',
        'Data3': '10.13476858762435E+001',
        'Data2': '10.954576354'
    }
]

答案 2 :(得分:0)

一种非常简单的方法可能是

all_objects = []

with open("datafile") as f:
    for L in f:
        if L[:3] == "***":
            # Line starts with asterisks, create a new object
            all_objects.append({})
        elif ":" in L:
            # Line is a key/value field, update current object
            k, v = map(str.strip, L.split(":", 1))
            all_objects[-1][k] = v