Encuentra la frase nominal antes y después de un número en un texto
Dado un texto, tengo que encontrar las palabras anteriores a todos los números hasta una palabra vacía que pertenezca a una lista check_words (tipo de palabras vacías).
Mi código:
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()
En ese texto en particular, verificaría antes '78'
y '45'
retrocederé hasta el punto en que encuentre cualquiera de las palabras en check_words (pero no más de 8 palabras).
El código para hacerlo podría ser:
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
Este código funciona. básicamente compruebo cada palabra pero tengo la impresión (tal vez me equivoque) de que se puede lograr con un par de frases de una sola línea y, por lo tanto, sin bucles. ¿Alguna idea?
NOTA: Esta pregunta se trata de mejorar la legibilidad del código, tratar de deshacerse de los bucles para hacer que el código sea más rápido e intentar que el código sea más agradable, lo cual es parte del Zen de Python.
NOTA 2: Algunas comprobaciones anteriores que hice:
- Encontrar la posición de un elemento en otra lista a partir de un número en una lista diferente
- Encontrar el índice de un elemento en una lista
- Buscar en la lista
Respuestas
Se me ocurrió esto:
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)
Aplicamos itertools.takewhile
al reversed_chunk
que nos da el trozo anterior en orden inverso. Luego obtenemos el orden correcto preceding_chunk
invirtiendo al final con [::-1]
.
La expresión regular se divide mystring
en función de un número (el escape \d+
). Las s escapadas circundantes \s+
representan cualquier relleno alrededor del número. Esto hace que este código tenga un comportamiento diferente al suyo si se mezclan dígitos y letras en las mismas palabras (por ejemplo, a1
).
Para su código original, haría un par de sugerencias:
- Siga PEP 8 . Por ejemplo, agregue espacio después de la coma en
i,word
. - Elimina la expresión redundante
preceding_words[::-1]
. Si bien esto se evalúa a la inversapreceding_words
, debido a que no está en el lugar, la evaluación no tiene efectos secundarios. Además, ya realiza esta inversión enenumerate(preceding_words[::-1])
.