Todavía soy nuevo en las expresiones regulares, como en la biblioteca de Python re.

Quiero extraer todos los nombres propios como una palabra completa si están separados por espacio.

Lo intenté

result = re.findall(r'(\w+)\w*/NNP (\w+)\w*/NNP', tagged_sent_str)

Entrada: tengo una cadena como

tagged_sent_str = "European/NNP Community/NNP French/JJ European/NNP export/VB" 

Salida esperada:

[('European Community'), ('European')]

Salida de corriente:

[('European','Community')]

Pero esto solo dará los pares, no los únicos. Quiero todos los tipos

1
Nancy Goyal 29 sep. 2019 a las 06:53

3 respuestas

La mejor respuesta

Requisito interesante. El código se explica en los comentarios, una solución muy rápida que utiliza solo REGEX:

import re
# make it more complex
text = "export1/VB European0/NNP export/VB European1/NNP Community1/NNP Community2/NNP French/JJ European2/NNP export/VB European2/NNP"


# 1: First clean app target words word/NNP to word,
#  you can use str.replace but just to show you a technique
# how to to use back reference of the group use \index_of_group
# re.sub(r'/NNP', '', text)
# text.replace('/NNP', '')
_text = re.sub(r'(\w+)/NNP', r'\1', text)

# this pattern strips the leading and trailing spaces
RE_FIND_ALL = r'(?:\s+|^)((?:(?:\s|^)?\w+(?=\s+|$)?)+)(?:\s+|$)'
print('RESULT : ', re.findall(RE_FIND_ALL, _text))

Salida:

  RESULT :  ['European0', 'European1 Community1 Community2', 'European2', 'European2']

Explicando REGEX:

  • (?:\s+|^): omite los espacios iniciales

  • ((?:(?:\s)?\w+(?=\s+|$))+): captura un grupo de subgrupo no copture (?:(?:\s)?\w+(?=\s+|$)) subgrupo coincidirá con todas las palabras de secuencia seguidas por espacios o final de línea. y ese partido será capturado por el grupo global. Si no hacemos esto, el partido devolverá solo la primera palabra.

  • (?:\s+|$): elimina el espacio final de la secuencia

Necesitaba eliminar /NNP de las palabras de destino porque desea mantener la secuencia de word/NNP en un solo grupo, haciendo algo como esto (word)/NNP (word)/NPP esto devolverá dos elementos en un grupo pero no como un solo texto, por lo que al eliminarlo, el texto será word word para que REGEX ((?:\w+\s)+) capture la secuencia de la palabra, pero no es tan simple como esto porque necesitamos capturar la palabra que no contiene /sequence_of_letter al final, no es necesario recorrer los grupos coincidentes para concatenar el elemento y crear un texto válido.

NOTA : ambas soluciones funcionan bien si todas las palabras están en este formato word/sequence_of_letters; si tienes palabras que no están en este formato necesitas arreglar eso. Si desea mantenerlos, agregue /NPP al final de cada palabra, de lo contrario, agregue /DUMMY para eliminarlos.

Usando re.split pero lento porque estoy usando list comprehensive para arreglar el resultado:

import re
# make it more complex
text = "export1/VB Europian0/NNP export/VB Europian1/NNP Community1/NNP Community2/NNP French/JJ Europian2/NNP export/VB Europian2/NNP export/VB export/VB"

RE_SPLIT = r'\w+/[^N]\w+'
result = [x.replace('/NNP', '').strip() for x in re.split(RE_SPLIT, text) if x.strip()]
print('RESULT:  ', result)    
0
Charif DZ 29 sep. 2019 a las 10:40

IIUC, itertools.groupby es más adecuado para este tipo de trabajo:

from itertools import groupby

def join_token(string_, type_ = 'NNP'):
    res = []
    for k, g in groupby([i.split('/') for i in string_.split()], key=lambda x:x[1]):
        if k == type_:
            res.append(' '.join(i[0] for i in g))
    return res

join_token(tagged_sent_str)

Salida:

['European Community', 'European']

Y no requiere una modificación si espera tres o más tipos consecutivos:

str2 = "European/NNP Community/NNP Union/NNP French/JJ European/NNP export/VB" 

join_token(str2)

Salida:

['European Community Union', 'European']
1
tripleee 29 sep. 2019 a las 10:42

Le gustaría obtener un patrón pero con algunas partes eliminadas de él. Puede obtenerlo con dos expresiones regulares sucesivas:

tagged_sent_str = "European/NNP Community/NNP French/JJ European/NNP export/VB"                                      

[ re.sub(r"/NNP","",s) for s in re.findall(r"\w+/NNP(?:\s+\w+/NNP)*",tagged_sent_str) ]                               
['European Community', 'European']
0
tripleee 29 sep. 2019 a las 10:41
58152101