Trouver la phrase nominale avant et après un nombre dans un texte
Étant donné un texte, je dois trouver les mots précédents à tous les nombres jusqu'à un mot vide appartenant à une liste check_words (sorte de mots vides).
Mon code :
check_words = ['the', 'a', 'with','to']
mystring = 'the code to find the beautiful words 78 that i have to nicely check 45 with the snippet'
list_of_words = mystring.split()
Dans ce texte particulier, je vérifierais avant '78'
et je '45'
reviendrais en arrière jusqu'au point où je trouverais l'un des mots dans check_words (mais pas plus de 8 mots).
Le code pour faire cela pourrait être:
preceding_chunks = []
for i,word in enumerate(list_of_words):
if any(char.isdigit() for char in word):
# 8 precedent words (taking into account that I can not slice with 8 back at the beginning)
preceding_words = list_of_words[max(0,i-8):i]
preceding_words[::-1]
# I check from the end of the list towards the start
for j,sub_word in enumerate(preceding_words[::-1]):
if sub_word in check_words:
# printing out j for checking
myposition = j
print(j)
real_preceding_chunk = preceding_words[len(preceding_words)-j:]
print(real_preceding_chunk)
preceding_chunks.append(real_preceding_chunk)
break
Ce code fonctionne. fondamentalement, je vérifie chaque mot. Mais j'ai l'impression (peut-être que je me trompe) que cela peut être réalisé avec quelques doublures et donc sans boucles. Une idée?
REMARQUE : Cette question porte sur l'amélioration de la lisibilité du code, en essayant de se débarrasser des boucles pour rendre le code plus rapide et en essayant de rendre le code plus agréable, ce qui fait partie du Zen de Python.
NOTE 2 : Quelques vérifications précédentes que j'ai effectuées :
- Trouver la position d'un élément dans une autre liste à partir d'un numéro dans une autre liste
- Trouver l'index d'un élément dans une liste
- Rechercher dans la liste
Réponses
Je suis venu avec ceci:
import itertools
import re
chunks = (grouped_chunk.split() for grouped_chunk in re.split("\\s+\\d+\\s+", mystring))
preceding_chunks = []
for reversed_chunk in map(reversed, chunks):
preceding_chunk = list(itertools.takewhile(lambda word: word not in check_words, reversed_chunk))[::-1]
preceding_chunks.append(preceding_chunk)
Nous appliquons itertools.takewhile
au reversed_chunk
qui nous donne le morceau précédent dans l'ordre inverse. On obtient alors le bon ordre preceding_chunk
en inversant à la fin avec [::-1]
.
La regex se divise mystring
en fonction d'un nombre (le escaped \d+
). Les s échappés environnants \s+
représentent tout remplissage autour du nombre. Cela fait que ce code a un comportement différent du vôtre si des chiffres et des lettres sont mélangés dans les mêmes mots (par exemple, a1
).
Pour votre code d'origine, je ferais quelques suggestions :
- Suivez PEP 8 . Par exemple, ajoutez un espace après la virgule dans
i,word
. - Supprimez l'expression redondante
preceding_words[::-1]
. Bien que cela soit évalué à l'inversepreceding_words
, car il n'est pas en place, l'évaluation n'a aucun effet secondaire. De plus, vous effectuez déjà cette inversion dansenumerate(preceding_words[::-1])
.