2015-01-06 3 views
8

Mit Python möchte ich in einem Wörterbuch alle Zeilen in einer Textdatei lesen, die hinter einer bestimmten Zeichenfolge stehen. Ich würde das gerne über Tausende von Textdateien machen.Wie liest man Zeilen in einer Textdatei nur nach einer bestimmten Zeichenfolge mit Python?

ich in der Lage bin zu identifizieren und die bestimmte Zeichenfolge (‚Abstract‘) mit dem folgenden Code ausdrucken (bekommen von this stack overflow answer):

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

Aber wie kann ich feststellen, Python die Zeilen lesen zu beginnen, kommt nur nach der Schnur?

Antwort

14

nur eine weitere Schleife starten, wenn Sie die Zeile, die Sie aus starten wollen erreichen:

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 

Ein Dateiobjekt ist es eigenen Iterator ist, so dass, wenn wir die Linie mit Zusammenfassung es erreichen wir unsere Iteration aus, dass Zeile, bis wir den Iterator verbraucht haben.

Ein einfaches Beispiel:

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 

Sie können auch itertools.dropwhile verwenden, um die Zeilen bis zu dem Punkt, Sie wollen zu konsumieren.

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) 
+0

Es funktioniert, aber es ist irgendwie komisch, meinst du nicht? und jeder, der nicht versteht, wie Generatoren arbeiten, wird sich den Kopf kratzen, warum er eine korrekte Ausgabe produziert. – Kroltan

+0

@Kroltan, nun, ich nehme an, dass Leute, die Python betrachten, wissen, wie Python-Code funktioniert. Das ist ziemlich einfach Python –

+0

Gut, aber ich wäre nicht so sicher, dass das OP davon bewusst ist. – Kroltan

7

eine boolean Verwenden Linien zu ignorieren bis zu diesem Punkt:

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 
+0

Diese Lösung beantwortet auch die Frage, die ich gestellt habe. –

4

Nur um zu klären, Ihr Code bereits alle Linien „liest“. Um zu beginnen, Zeilen nach einem bestimmten Punkt "aufmerksam zu machen", können Sie einfach ein boolesches Flag setzen, um anzugeben, ob Zeilen ignoriert werden sollen, und es an jeder Zeile überprüfen.

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 

Wenn Sie nicht ein wenig mehr Umordnung des Codes nichts dagegen haben, können Sie stattdessen auch zwei Teilschleifen verwenden: eine Schleife, die einmal beenden Sie Ihren Trigger-Satz ('Abstract') gefunden haben, und eine, die alle folgenden Zeilen liest. Dieser Ansatz ist ein wenig sauberer (und ein sehr kleines bisschen schneller).

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 

Der Grund dieser Arbeiten ist, dass das Dateiobjekt von open verhält sich wie ein generator zurückgekehrt, eher als, sagen wir, eine Liste: Sie produziert nur Werte, wie sie angefordert werden. Wenn die erste Schleife stoppt, bleibt die interne Position der Datei am Anfang der ersten "ungelesenen" Zeile. Das bedeutet, wenn Sie die zweite Schleife eingeben, ist die erste Zeile, die Sie sehen, die erste Zeile nach der, die die break ausgelöst hat.

+0

Diese Lösung hat auch die Frage beantwortet, die ich gestellt habe. –

5

Sie itertools.dropwhile und itertools.islice hier verwenden können, ein pseudo-Beispiel:

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 
+0

Ich mag das ... Immer überrascht von 'itertools'! – Kroltan

+0

Ich wurde für Dropwhile bis dann Ihre ans erschienen, nett, +1 – Hackaholic

1

eine Vermutung zu machen, wie das Wörterbuch beteiligt ist, würde ich es auf diese Weise schreiben:

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) 

Also für jede Datei enthält Ihr Wörterbuch ein Tupel von Zeilen.

Dies funktioniert, weil die Schleife bis einschließlich der identifizierten Zeile liest und die restlichen Zeilen in der Datei bereit zum Lesen aus f bleibt.

3

Für mich ist der folgende Code leichter zu verstehen.

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' 
+1

Ich bekomme AttributeError: '_io.TextIOWrapper' Objekt hat kein Attribut 'nächste' – yehudahs

+0

Hoy verwenden wahrscheinlich Python 3.0. Probieren Sie 'next (f)' anstelle von 'f.next()' aus und lassen Sie mich wissen, ob es funktioniert. – eguaio

+0

funktioniert ... thx !! – yehudahs