9

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

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

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

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

有什么想法吗?

4

3 回答 3

10

实际上,它与 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] = valuedo entry[key] = converters.get(key, lambda v: v)(value)

于 2013-06-14T09:46:28.543 回答
4

我的文件:

******** 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'
    }
]
于 2013-06-14T09:43:41.340 回答
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
于 2013-06-14T10:00:25.503 回答