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」を使用すると、「while not end of file」として機能するということでした。最初の 16 行をスキップした後、「while True」を追加してみました。私は Python の解析機能についてほとんど知識がありません。

助けてくれてありがとう。

4

3 に答える 3

3

最初のスキップの後に a を追加すると、while True間違いなく機能するはずです。もちろん、すべての詳細を正しく取得する必要があります。

外側のループ内にネストされたループを使用して、既に使用しているアプローチを拡張することができます。whileしかし、それを単一のループと考えた方が簡単かもしれません。各行で行う必要があるのは、次の 3 つのみです。

  • 行がない場合は、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:代わりに aを使用します。whilef.readline()
  • groupby行の反復子を空白行で区切られた行グループの反復子に変換するために使用します。
于 2015-05-26T01:05:49.653 に答える
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 に答える
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 に答える