Necesito hacer una lista de cada par de palabras secuencialmente en una cadena con una expresión regular, la parte relevante del código es esta:

for word in re.findall(r'\w+\b.*?\w+', text):

Ahora tomemos como ejemplo el texto "Este es un texto aleatorio" , lo que quiero es una lista como esta:

['Esto es', 'es un', 'aleatorio', 'texto aleatorio']

En cambio, lo que obtengo es esto:

['Esto es', 'aleatorio']

¿Cómo puedo arreglar esto? Gracias por adelantado.

1
Zarok 28 sep. 2019 a las 04:37

5 respuestas

La mejor respuesta

Dijiste que las palabras están separadas por una cantidad aleatoria de espacios y / o puntuación, Usé [\s\.]+ para eso.

Lo que está haciendo mal aquí es que está consumiendo la segunda palabra, lo que necesita es una anticipación positiva que coincida con la segunda palabra pero no la consuma, por lo que coincidirá la próxima vez. y porque dijiste que es un Texto masivo, creo que usar finditer es mejor que findall. La diferencia es que devuelve un generador que produce los mismos elementos devueltos por findall:

import re

text ="""This. is a random text"""

pattern = re.compile(r'(\w+[\s\.]+)(?=(\w+))')
for match in pattern.finditer(text):
    # rebuild the word
    element = ''.join(match.groups())
    print(element)

Ouput:

This. is
is a
a random
random text

Tenga en cuenta que, por defecto, la búsqueda anticipada positiva no es un grupo de captura, por eso hice esto (?=(\w+)) para capturar la palabra dentro de él. El primer grupo es (\w+[\s\.]+). y usé join para reconstruir concatenar los grupos nuevamente.

2
Charif DZ 28 sep. 2019 a las 08:00

No necesita usar expresiones regulares para este caso, solo puede usar dividir

st = "This is a random text"
sp = st.split()

result = [f"{w1} {w2}" for w1, w2 in zip(sp, sp[1:])]
print(result)

resultado

['This is', 'is a', 'a random', 'random text']

Editar

Para datos grandes puede implementar generador. como pseudocódigo debajo

def get_pair_from_large_text():
    tail_of_last_chunk = ""
    while True
        chunk = get_string_chunk_from_source()
        if len(chunk)==0:
            yield f"{words[-2]} {words[-1]}"
            break
        chunk = tail_of_last_chunk[1] + chunk

        words = split(chunk)
        tail_of_last_chunk = words[-2], words[-1]

        for w1, w2 in zip(words[:-1], words[1:-1])
            yield f"{w1} {w2}"


0
Nick 28 sep. 2019 a las 02:22

¿Pero realmente necesitas regex? Puedes hacerlo sin expresiones regulares

L1 = line.split(' ')
L2 = L1[1:].append(' ')
Result = [' '.join(a,b) for a,b in zip(L1,L2)]

Usando Regex pero el resultado no está en orden

>>> pattern1 = re.compile(r"(\w+\s+\w+)")
>>> pattern2 = re.compile(r"(\s+\w+\s+\w+)")
>>> l1 = re.findall(pattern1, line)
>>> l2 =[x.strip() for x in re.findall(pattern2, line)]
>>> l1
['This is', 'a random']
>>> l2
['is a', 'random text']
>>> l1 + l2
['This is', 'a random', 'is a', 'random text']
0
abhilb 28 sep. 2019 a las 03:01

Por lo general, no creo que el mismo RegEx permita la superposición de resultados de búsqueda. Lo que quizás quieras hacer en su lugar es encontrar los espacios intermedios y las palabras que están justo antes y justo después del espacio.

0
Prometheus 28 sep. 2019 a las 01:43

Si desea utilizar expresiones regulares para esta tarea, eche un vistazo a esto:

(\w+)\s+(?=(\w+))

Demostración de Regex

El truco consiste en utilizar búsqueda anticipada positiva para la segunda palabra y capturarla dentro de un grupo. Para generar los pares resultantes, combine el resultado de las coincidencias del Grupo 1 y el Grupo 2.

1
vs97 28 sep. 2019 a las 01:59
58142724