web-dev-qa-db-ja.com

Pythonを使用して特定の文字列の後にテキストファイルの行のみを読み取る方法は?

Pythonを使用して、特定の文字列の後にあるテキストファイル内のすべての行を辞書に読みたいです。数千のテキストファイルでこれを実行したいと思います。

次のコード( this stack overflow answer から取得)を使用して、特定の文字列( 'Abstract')を識別および印刷できます。

for files in filepath:
    with open(files, 'r') as f:
        for line in f:
            if 'Abstract' in line:
                print line;

しかし、pythonに、文字列の後にのみ来る行の読み取りを開始するように指示するにはどうすればよいですか?

11
Brian Zelip

開始したい行に到達したら、別のループを開始します。

for files in filepath:
    with open(files, 'r') as f:
        for line in f:
            if 'Abstract' in line:                
                for line in f: # now you are at the lines you want
                    # do work

ファイルオブジェクトはそれ自身のイテレータです。そのため、Abstractを含む行に到達すると、イテレータを消費するまでその行から繰り返しを続けます。

簡単な例:

gen  =  (n for n in xrange(8))

for x in gen:
    if x == 3:
        print("starting second loop")
        for x in gen:
            print("In second loop",x)
    else:
        print("In first loop", x)

In first loop 0
In first loop 1
In first loop 2
starting second loop
In second loop 4
In second loop 5
In second loop 6
In second loop 7

itertools.dropwhile を使用して、必要なポイントまでの行を消費することもできます。

from itertools import dropwhile

for files in filepath:
    with open(files, 'r') as f:
        dropped = dropwhile(lambda _line: "Abstract" not in _line, f)
        next(dropped,"")
        for line in dropped:
                print(line)
19

ブール値を使用して、その時点までの行を無視します。

found_abstract = False
for files in filepath:
    with open(files, 'r') as f:
        for line in f:
            if 'Abstract' in line:
                found_abstract = True
            if found_abstract:
                #do whatever you want
8
Kroltan

ここでは、itertools.dropwhileitertools.isliceを使用できます。擬似例です。

from itertools import dropwhile, islice

for fname in filepaths:
    with open(fname) as fin:
        start_at = dropwhile(lambda L: 'Abstract' not in L.split(), fin)
        for line in islice(start_at, 1, None): # ignore the line still with Abstract in
            print line
8
Jon Clements

私にとって、次のコードは理解しやすいです。

with open(file_name, 'r') as f:
    while not 'Abstract' in next(f):
        pass
    for line in f:
        #line will be now the next line after the one that contains 'Abstract'
4
eguaio

明確にするために、コードalreadyはすべての行を「読み取り」ます。特定のポイントの後に行に「注意を払う」ために、行を無視するかどうかを示すブールフラグを設定し、各行でそれを確認することができます。

pay_attention = False
for line in f:
    if pay_attention:
        print line
    else:  # We haven't found our trigger yet; see if it's in this line
        if 'Abstract' in line:
            pay_attention = True

コードをもう少し再配置する必要がない場合は、代わりに2つの部分ループを使用することもできます。トリガーフレーズ('Abstract')、およびすべての後続の行を読み取るもの。このアプローチは少しきれいです(非常にわずかに高速です)。

for skippable_line in f:  # First skim over all lines until we find 'Abstract'.
    if 'Abstract' in skippable_line:
        break
for line in f:  # The file's iterator starts up again right where we left it.
    print line

これが機能する理由は、openによって返されるファイルオブジェクトが、リストなどではなく generator のように動作するためです。要求された値のみを生成します。したがって、最初のループが停止すると、ファイルは最初の「未読」行の先頭に設定された内部位置のままになります。つまり、2番目のループに入ると、最初の行はbreakをトリガーした行の後の最初の行になります。

4
Henry Keiter

辞書がどのように関係しているかを推測して、このように書きます:

lines = dict()
for filename in filepath:
   with open(filename, 'r') as f:
       for line in f:
           if 'Abstract' in line:
               break
       lines[filename] = Tuple(f)

そのため、各ファイルについて、辞書にはタプルの行が含まれています。

これは、ループが特定の行まで読み取り、ファイル内の残りの行をfから読み込めるようにするためです。

1
Steve Jessop