解析换行符分隔文件

时间:2015-05-26 00:54:08

标签: python fileparsing

我正在开发一个项目,我想用Python解析文本文件。该文件由一些数据条目组成,这些数据条目的格式可以变化。有新行时会找到新条目。这就是我想要实现的目标:

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

    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的解析功能知之甚少。

    感谢您提前获取任何帮助。

3 个答案:

答案 0 :(得分:3)

在初始跳过后添加while 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)

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

  • 使用for line in f:而不是重复执行while的{​​{1}}循环并对其进行检查。
  • 使用groupby将行的迭代器转换为以空行分隔的行组的迭代器。

答案 1 :(得分: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分组分开。

答案 2 :(得分: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