Estoy tratando de limpiar algunos cuerpos de texto en Python 3 eliminando palabras alfanuméricas (palabras que contienen letras y números), pero hay algunas excepciones que me gustaría permanecer en el texto. El siguiente código elimina todas las palabras alfanuméricas del texto:

import re

string1 = "3n3k game gnma34 xbox360 table"
string2 = "the a22b b3kj3 ps4 2ij2aln potato"

new_string1 = re.sub(r'\w*\d\w*', '', string1)
new_string2 = re.sub(r'\w*\d\w*', '', string2)

El código anterior produce new_string1 que es "mesa de juego" y new_string2 que es "la papa". Lo que necesito es que new_string1 sea "game xbox360 table" y new_string2 sea "the ps4 potato".

Me imagino que puedo crear una serie de excepciones, por ejemplo:

exceptions = ['xbox360', 'ps4'] #there may be many more exceptions than this

Pero no estoy muy seguro de cómo incorporar esta lista de excepciones en mi expresión regular (soy bastante nuevo en el concepto). Cualquier idea es muy apreciada!

1
Rudy 28 oct. 2017 a las 03:43

3 respuestas

La mejor respuesta

Use un enfoque bidireccional: divida y analice las palabras:

import re

strings = ["3n3k game gnma34 xbox360 table", "the a22b b3kj3 ps4 2ij2aln potato"]
exceptions = ['xbox360', 'ps4']

def cleanse(word):
    rx = re.compile(r'\D*\d')
    if rx.match(word) and word not in exceptions:
        return ''
    return word

nstrings = [" ".join(filter(None, (
    cleanse(word) for word in string.split()))) 
    for string in strings]
print(nstrings)
# ['game xbox360 table', 'the ps4 potato']

`\D*\d`

E intente hacerlas coincidir al comienzo de cada "palabra" (con re.match()) ya que \w también contiene dígitos.


nuevo módulo regex (*SKIP)(*FAIL)
\b(?:xbox360|ps4)\b   # define your exceptions
(*SKIP)(*FAIL)        # these shall fail
|                     # or match words with digits
\b[A-Za-z]*\d\w*\b

Consulte una demostración en regex101.com y la {{ X0}} fragmento aquí:

import regex as re

strings = ["3n3k game gnma34 xbox360 table", "the a22b b3kj3 ps4 2ij2aln potato  123123 1234"]
exceptions = [r'\d+', 'xbox360', 'ps4']

rx = re.compile(r'\b(?:{})\b(*SKIP)(*FAIL)|\b[A-Za-z]*\d\w*\b'.format("|".join(exceptions)))

nstrings = [" ".join(
    filter(None, (rx.sub('', word) 
    for word in string.split()))) 
    for string in strings]
print(nstrings)
# ['game xbox360 table', 'the ps4 potato 123123 1234']
1
Jan 30 oct. 2017 a las 18:28

Use una mirada negativa hacia adelante. Una anticipación negativa es longitud cero : no coincide con nada; tiene éxito o falla, y, una vez hecho, el cursor todavía está donde estaba antes. Por lo tanto, desea verificar el límite de una palabra (\b), verifique que el siguiente texto no esté en su lista de excepciones ((?!...)) y use su expresión regular existente para que coincida con la palabra ({{ X2}}).

Para construir el cuerpo de la búsqueda anticipada, simplemente concatene los elementos de exceptions junto con un | en el medio, o simplemente haga exceptions una expresión regular que coincida con las palabras que desea mantener directamente.

No estoy muy familiarizado con Python, así que así es como debería verse la expresión regular en el caso de ejemplo, y espero que pueda generalizar:

\b(?!xbox360|ps4)\w*\d\w*

Para eliminar espacios en blanco

" ".join(re.sub(r'\b(?!xbox360|ps4)\w*\d\w*'," ",string1).split())
3
Sandeep Lade 28 oct. 2017 a las 04:37

No pude encontrar una expresión regular para ti, pero aquí hay una forma de lograrlo

>>> exceptions = ['xbox360', 'ps4']
>>> string1 = "3n3k game gnma34 xbox360 table"

>>> " ".join([i if i in exceptions else re.sub(r'\w*\d\w*', '', i) for i in string1.split()])
' game  xbox360 table'
>>> string2 = "the a22b b3kj3 ps4 2ij2aln potato"

>>> " ".join([i if i in exceptions else re.sub(r'\w*\d\w*', '', i) for i in string2.split()])
'the   ps4  potato'
1
Sandeep Lade 28 oct. 2017 a las 04:21