web-dev-qa-db-fra.com

Comment lire uniquement les lignes d'un fichier texte après une certaine chaîne en utilisant python?

En utilisant python, je voudrais lire dans un dictionnaire toutes les lignes d'un fichier texte qui viennent après une chaîne particulière. Je voudrais le faire sur des milliers de fichiers texte.

Je peux identifier et imprimer la chaîne particulière ('Abstract') en utilisant le code suivant (obtenu de cette réponse de débordement de pile ):

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

Mais comment dire à python de commencer à lire les lignes qui viennent seulement après la chaîne?

11
Brian Zelip

commencez simplement une autre boucle lorsque vous atteignez la ligne à partir de laquelle vous souhaitez commencer:

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

Un objet fichier est son propre itérateur, donc lorsque nous atteignons la ligne avec Résumé, nous continuons notre itération à partir de cette ligne jusqu'à ce que nous ayons consommé l'itérateur.

Un exemple simple:

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

Vous pouvez également utiliser itertools.drop while pour consommer les lignes jusqu'au point souhaité.

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
Padraic Cunningham

Utilisez un booléen pour ignorer les lignes jusqu'à ce point:

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

Vous pouvez utiliser itertools.dropwhile et itertools.islice ici, un pseudo-exemple:

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

Pour moi, le code suivant est plus facile à comprendre.

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

Juste pour clarifier, votre code déjà "lit" toutes les lignes. Pour commencer à "faire attention" aux lignes après un certain point, vous pouvez simplement définir un indicateur booléen pour indiquer si les lignes doivent être ignorées ou non, et le vérifier à chaque ligne.

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

Si cela ne vous dérange pas un peu plus de réarrangement de votre code, vous pouvez également utiliser deux boucles partielles à la place: une boucle qui se termine une fois que vous avez trouvé votre phrase de déclenchement ('Abstract'), et celui qui lit toutes les lignes suivantes. Cette approche est un peu plus propre (et un tout petit peu plus rapide).

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

La raison pour laquelle cela fonctionne est que l'objet fichier renvoyé par open se comporte comme un générateur , plutôt que, disons, une liste: il ne produit que des valeurs telles qu'elles sont demandées. Ainsi, lorsque la première boucle s'arrête, le fichier est laissé avec sa position interne définie au début de la première ligne "non lue". Cela signifie que lorsque vous entrez dans la deuxième boucle, la première ligne que vous voyez est la première ligne après celle qui a déclenché le break.

4
Henry Keiter

En devinant comment le dictionnaire est impliqué, je l'écrirais de cette façon:

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)

Ainsi, pour chaque fichier, votre dictionnaire contient un Tuple de lignes.

Cela fonctionne car la boucle lit jusqu'à et y compris la ligne que vous identifiez, laissant les lignes restantes dans le fichier prêtes à être lues à partir de f.

1
Steve Jessop