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?
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)
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
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
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'
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
.
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
.