Contar la presencia de palabras dentro del contexto cerca de otras palabras

Estoy tratando de evaluar si dos grupos de palabras con nombre aparecen dentro de las 25 palabras entre sí. Tengo dos problemas, que probablemente estén muy interrelacionados:

  1. Estoy siguiendo este enfoque para evaluar si ciertas palabras están cerca unas de otras http://www.regular-expressions.info/near.html . El contador original parece funcionar, pero luego quiero dividir mi código en dos partes para verificarlo dos veces. Sin embargo, cuando lo hago, mi "counter3" crea un problema de conteo doble (es decir, cuenta las palabras compradas cuando solo debería contar las ventas). Esta es casi exactamente la misma pregunta y problema que Contar la presencia de palabras dentro del contexto (cerca de otras palabras), excepto que se usa Python en lugar de Perl .
text = "CompanyA sells Androids and Robots. Androids are then purchased and resold by Company"

counter1 = Counter(re.findall(r'\b((?:Androids\W+(?:\w+\W+){0,25}?\W+sells|purchased|resold)|sells|purchased|resold\W+(?:\w+\W+){0,25}?Androids)\b',text, re.DOTALL))

#to ensure my code is working correctly, I then want to split counter1 into two parts. However, counter 3 is giving me a double counting issues: 
counter2 = Counter(re.findall(r'\b((?:Androids\W+(?:\w+\W+){0,25}?/W+sells|purchased|resold))\b',text, re.DOTALL))
counter3 = Counter(re.findall(r'\b((?:sells|purchased|resold\W+(?:\w+\W+){0,25}?/W+Androids))\b',text, re.DOTALL))

#Result: counter1= Counter({'sells': 1, 'purchased': 1, 'resold': 1})
#Result: counter2 = Counter({'purchased': 1, 'resold': 1})
#Result: counter3= Counter({'sells': 1, 'purchased': 1})


#I have also tried the below variation, which corrects counter3, but then causes an issue with counter2
counter2 = Counter(re.findall(r'\b((Androids)\W+(?:\w+\W+){0,25}?(sells|purchased|resold))\b',text, re.DOTALL))
counter3 = Counter(re.findall(r'\b((sells|purchased|resold)\W+(?:\w+\W+){0,25}?(Androids))\b',text, re.DOTALL))

#result counter2 = Counter({('Androids and Robots. Androids are then purchased',           'Androids','purchased'): 1})
#result counter3 = Counter({('sells Androids', 'sells', 'Androids'): 1})

  1. A continuación, quiero crear variables para los grupos de palabras y luego hacer referencia a ellas dentro de mi expresión regular. Estoy siguiendo esta referencia ¿Cómo usar una variable dentro de una expresión regular? . Sin embargo, todavía tengo problemas (tal vez una vez que se responda la pregunta 1, me lleve a la respuesta de la pregunta 2)
Group1 ='Androids'
Group2 = 'sells |purchased |resold '

counter2 = Counter(re.findall(rf'\b(?:{Group1}\W+(?:\w+\W+){0,25}?{Group2})\b',text, re.DOTALL))
counter3 = Counter(re.findall(rf'\b(?:{Group2}\W+(?:\w+\W+){0,25}?{Group1})\b',text, re.DOTALL))


#Result - counter2 = Counter({'': 2})
#Result - counter3 = Counter({'': 2})

#interestingly, if I try an alternative variation (i.e., removing ?:), which fixed counter3 in my first question, it does not fix the issue when I try to reference the variables 

counter2 = Counter(re.findall(rf'\b({Group1}\W+(?:\w+\W+){0,25}?{Group2})\b',text, re.DOTALL))
counter3 = Counter(re.findall(rf'\b({Group2}\W+(?:\w+\W+){0,25}?{Group1})\b',text, re.DOTALL))

#Result - counter2 = Counter({('purchased ', ''): 1, ('resold ', ''): 1})
#Result counter3 = Counter({('sells ', ''): 1, ('purchased ', ''): 1})

¡Cualquier ayuda sería fantástica, ya que siento que me estoy volviendo un poco loco probando diferentes variaciones para hacer que este código funcione! ¡Gracias!

Answer

Si está buscando 'Androides' separados por uno de 'vende' o 'comprado' o 'revendido' dentro de 25 palabras, lo siguiente encontrará todas las coincidencias y le dará un recuento de todas las coincidencias de las palabras que abarcan las coincidencias . Si desea algo diferente, debe decir lo que desea en un lenguaje sencillo (esto se basa estrictamente en el enlace que proporcionó el OP con sustituciones simples pero lógicas ):

import re
from collections import Counter

text = "CompanyA sells Androids and Robots. Androids are then purchased and resold by Company"
regex = r'\b(?:Androids\W+(?:\w+\W+){0,25}?(?:sells|purchased|resold)|(?:sells|purchased|resold)\W+(?:\w+\W+){0,25}?Androids)\b'
matches = re.findall(regex, text)
print(matches)
c = Counter()
for match in matches:
    c.update(match.split())
print(c)

Huellas dactilares:

['sells Androids', 'Androids are then purchased']
Counter({'Androids': 2, 'sells': 1, 'are': 1, 'then': 1, 'purchased': 1})

Cuando inserta lo que está buscando en el patrón proporcionado por el enlace, que fue diseñado para coincidencias de una sola palabra, debido a que tiene una situación "o" (es decir, una elección de palabras que satisface una coincidencia), debe, debido a precedencia, use paréntesis alrededor del grupo de palabras que están separadas por |. Y para no introducir un grupo de captura adicional, debe ser un paréntesis de no captura, es decir (?: ... ).

Ahora, si quieres contar las cosas de manera diferente, usa esto como punto de partida. Pero tenga en cuenta lo que sucede cuando comienza a agregar grupos de captura en cuanto a cómo afecta el findallmétodo.