3

我正在做一个项目,我想使用 Python 解析文本文件。该文件由不同块格式的一些数据条目组成。当有新行时,会找到一个新条目。这就是我想要完成的:

  1. 跳过前几行(前 16 行)
  2. 第 16 行之后,有一个换行符开始新的数据输入
  3. 阅读以下几行,直到遇到新的换行符。每个单独的行都附加到一个称为数据的列表中。
  4. 该列表将被传递给处理进一步处理的函数。
  5. 重复步骤 3 和 4,直到文件中没有更多数据

以下是该文件的示例:

Header Info
More Header Info

Line1
Line2
Line3
Line4
Line5
Line6
Line7
Line8
Line9
Line10
Line11
Line12
Line13

MoreInfo    MoreInfo    MoreInfo    MoreInfo    MoreInfo
MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2
MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3
MoreInfo4   MoreInfo4
FieldName1  0001    0001
FieldName1  0002    0002
FieldName1  0003    0003
FieldName1  0004    0004
FieldName1  0005    0005
FieldName2  0001    0001
FieldName3  0001    0001
FieldName4  0001    0001
FieldName5  0001    0001
FieldName6  0001    0001

MoreInfo    MoreInfo    MoreInfo    MoreInfo    MoreInfo
MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2
MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3
MoreInfo4   MoreInfo4
FieldName1  0001    0001
FieldName1  0002    0002
FieldName1  0003    0003
FieldName1  0004    0004
FieldName1  0005    0005
FieldName2  0001    0001
FieldName3  0001    0001
FieldName4  0001    0001
FieldName5  0001    0001
FieldName6  0001    0001

这是我处理过的一些代码。它能够读取第一个块并将其附加到列表中:

with open(loc, 'r') as f:
    for i in range(16):
        f.readline()

    data = []
    line = f.readline()
    if line == "\n":
        dataLine = f.readline()
        while dataLine != "\n":
            data.append(dataLine)
            dataLine = f.readline()

    #pass data list to function
    function_call(data)
    # reset data list here?
    data = []

如何使它适用于完整文件?我的假设是使用“with open”,它充当“虽然不是文件结尾”。在跳过前 16 行后,我尝试添加“while True”。我对 Python 的解析能力知之甚少。

提前感谢您的任何帮助。

4

3 回答 3

3

在初始跳过之后添加 awhile True绝对应该有效。当然,您必须正确处理所有细节。

可以尝试扩展您已有的方法,while在外循环内使用嵌套循环。但将其视为单个循环可能更容易。对于每一行,您可能只需要做三件事:

  • 如果没有行,因为您在 EOF中,break请确保处理旧的data(文件中的最后一个块)(如果有的话)。
  • 如果它是一个空行,则开始一个新的,如果先有一个data,请确保处理旧的data
  • 否则,追加到现有的data.

所以:

with open(loc, 'r') as f:
    for i in range(16):
        f.readline()

    data = []
    while True:
        line = f.readline()
        if not line:
            if data:
                function_call(data)
            break
        if line == "\n":
            if data:
                function_call(data)
                data = []
        else:
            data.append(line)

有几种方法可以进一步简化:

  • 使用 afor line in f:而不是while重复执行f.readline()并检查它的循环。
  • 用于groupby将行的迭代器转换为以空行分隔的行组的迭代器。
于 2015-05-26T01:05:49.653 回答
0

如果您仍在为此苦苦挣扎,这里有一个使用itertools.groupby()和关键功能读取示例数据的实现search()

from itertools import groupby, repeat

def search(d):
    """Key function used to group our dataset"""

    return d[0] == "\n"

def read_data(filename):
    """Read data from filename and return a nicer data structure"""

    data = []

    with open(filename, "r") as f:
        # Skip first 16 lines
        for _ in repeat(None, 16):
            f.readline()

        # iterate through each data block
        for newblock, records in groupby(f, search):
            if newblock:
                # we've found a new block
                # create a new row of data
                data.append([])
            else:
                # we've found data for the current block
                # add each row to the last row
                for row in records:
                    row = row.strip().split()
                    data[-1].append(row)

    return data

这将产生一个嵌套的块列表的数据结构。\n每个子列表由数据文件中的分组分开。

于 2015-05-26T01:35:15.353 回答
0

文件中的块模式是它们由以空行或文件结尾终止的行组组成。这个逻辑可以封装在一个生成器函数中,该函数迭代地从文件中生成行块,这将简化脚本的其余部分。

下面getlines()是生成器函数。另请注意,跳过文件的前17行以到达第一个块的开头。

from pprint import pformat

loc = 'parsing_test_file.txt'

def function(lines):
    print('function called with:\n{}'.format(pformat(lines)))

def getlines(f):
    lines = []
    while True:
        try:
            line = next(f)
            if line != '\n':  # not end of the block?
                lines.append(line)
            else:
                yield lines
                lines = []
        except StopIteration:  # end of file
            if lines:
                yield lines
            break

with open(loc, 'r') as f:
    for i in range(17):
        next(f)

    for lines in getlines(f):
        function(lines)

print('done')

使用您的测试文件输出:

function called with:
['MoreInfo    MoreInfo    MoreInfo    MoreInfo    MoreInfo\n',
 'MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2\n',
 'MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3\n',
 'MoreInfo4   MoreInfo4\n',
 'FieldName1  0001    0001\n',
 'FieldName1  0002    0002\n',
 'FieldName1  0003    0003\n',
 'FieldName1  0004    0004\n',
 'FieldName1  0005    0005\n',
 'FieldName2  0001    0001\n',
 'FieldName3  0001    0001\n',
 'FieldName4  0001    0001\n',
 'FieldName5  0001    0001\n',
 'FieldName6  0001    0001\n']
function called with:
['MoreInfo    MoreInfo    MoreInfo    MoreInfo    MoreInfo\n',
 'MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2   MoreInfo2\n',
 'MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3   MoreInfo3\n',
 'MoreInfo4   MoreInfo4\n',
 'FieldName1  0001    0001\n',
 'FieldName1  0002    0002\n',
 'FieldName1  0003    0003\n',
 'FieldName1  0004    0004\n',
 'FieldName1  0005    0005\n',
 'FieldName2  0001    0001\n',
 'FieldName3  0001    0001\n',
 'FieldName4  0001    0001\n',
 'FieldName5  0001    0001\n',
 'FieldName6  0001    0001\n']
done
于 2015-05-26T03:32:59.520 回答