Python, elimine todos los caracteres que no sean del alfabeto de la cadena

90

Estoy escribiendo un programa de recuento de palabras en Python MapReduce. El problema es que hay muchos caracteres no alfabéticos esparcidos en los datos, he encontrado esta publicación Eliminando todo menos caracteres alfanuméricos de una cadena en Python que muestra una buena solución usando expresiones regulares, pero no estoy seguro de cómo implementarlo

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

Me temo que no estoy seguro de cómo usar la biblioteca reo incluso la expresión regular para el caso. No estoy seguro de cómo aplicar el patrón de expresiones regulares a la cadena entrante (línea de un libro) vcorrectamente para recuperar la nueva línea sin caracteres no alfanuméricos.

Sugerencias

KDecker
fuente
ves una línea completa de un libro (específicamente Moby Dick), voy palabra por palabra, no char por char. Así que algunas palabras pueden tener un "," al final, así que "indignidad" no se corresponde con "indignidad".
KDecker
Lolx - ¿Hiciste el mismo ejercicio en casa antes de la entrevista que yo? Encuentre las 50 palabras más utilizadas en Moby Dick e informe su frecuencia. Lo hice en C ++, IIRC
Mawg dice reinstalar a Monica
1
@Mawg Fue un ejercicio en mi clase de "Computación en la nube" de pregrado.
KDecker

Respuestas:

127

Utilizar re.sub

import re

regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', 'ab3d*E')
#Out: 'abdE'

Alternativamente, si solo desea eliminar un determinado conjunto de caracteres (ya que un apóstrofo podría estar bien en su entrada ...)

regex = re.compile('[,\.!?]') #etc.
limasxgoesto0
fuente
Hmm, puedo rastrearlo, pero ¿qué pasa con el patrón para eliminar todos los espacios no alfanuméricos excluyendo espacios?
KDecker
1
Simplemente agregue un espacio en su clase de colección. es decir, ^a-zA-Z en lugar de sólo^a-zA-Z
limasxgoesto0
A menos que también esté preocupado por las nuevas líneas, en cuyo caso a-zA-Z \n. Estoy tratando de encontrar una expresión regular que agrupe a ambos en uno, pero usando \wo \Wno me da el comportamiento deseado. Es posible que solo necesite agregar \nsi ese es el caso.
limasxgoesto0
Ahh, el carácter de nueva línea. Ahí es donde radican mis problemas, estaba comparando mis resultados con los resultados dados y todavía estaba fuera de lugar. ¡Creo que ese es mi problema! Gracias // Hmm, lo probé con el carácter de nueva línea mismos resultados, creo que hay otro que me falta .. // Duhhh ... Mayúsculas y minúsculas ... // Gracias por toda la ayuda, ¡funciona perfectamente ahora!
KDecker
48

Si prefiere no usar expresiones regulares, puede intentar

''.join([i for i in s if i.isalpha()])
Tad
fuente
¿cómo me uno a esto? con '' .unir? la impresión s obtiene solo un objeto de filtro
PirateApp
Vaya, esto es lo que estaba buscando. Esto tiene en cuenta kanji, hiragana, katakana, etc. kudos
root163
34

Puede utilizar la función re.sub () para eliminar estos caracteres:

>>> import re
>>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
'ABCabcdef'

re.sub (COINCIDIR PATRÓN, REEMPLAZAR CADENA, CADENA PARA BUSCAR)

  • "[^a-zA-Z]+" - busque cualquier grupo de caracteres que NO sean a-zA-z.
  • "" - Reemplazar los caracteres coincidentes con ""
Kevin
fuente
Tenga en cuenta que esto también eliminará las letras acentuadas: ãâàáéèçõ, etc.
Brad Ahrens
19

Tratar:

s = ''.join(filter(str.isalnum, s))

Esto tomará todos los caracteres de la cadena, mantendrá solo los alfanuméricos y construirá una cadena a partir de ellos.

Don
fuente
1
Esta respuesta podría necesitar mucha más explicación y enlaces a documentación relevante.
pdoherty926
4

El método más rápido es regex

#Try with regex first
t0 = timeit.timeit("""
s = r2.sub('', st)

""", setup = """
import re
r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
st = '[email protected]#$%^&*()-=_+'
""", number = 1000000)
print(t0)

#Try with join method on filter
t0 = timeit.timeit("""
s = ''.join(filter(str.isalnum, st))

""", setup = """
st = '[email protected]#$%^&*()-=_+'
""",
number = 1000000)
print(t0)

#Try with only join
t0 = timeit.timeit("""
s = ''.join(c for c in st if c.isalnum())

""", setup = """
st = '[email protected]#$%^&*()-=_+'
""", number = 1000000)
print(t0)


2.6002226710006653 Method 1 Regex
5.739747313000407 Method 2 Filter + Join
6.540099570000166 Method 3 Join
PirateApp
fuente
0

Es recomendable utilizar el módulo PyPiregex si planea hacer coincidir clases de propiedad Unicode específicas. Esta biblioteca también ha demostrado ser más estable, especialmente en el manejo de textos grandes, y produce resultados consistentes en varias versiones de Python. Todo lo que necesita hacer es mantenerlo actualizado.

Si lo instala (usando pip intall regexo pip3 install regex), puede usar

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

para eliminar todos los fragmentos de 1 o más caracteres que no sean letras Unicode de text. Vea una demostración de Python en línea . También puede utilizar "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))para obtener el mismo resultado.

En Python re, para hacer coincidir cualquier letra Unicode, se puede usar la [^\W\d_]construcción (¿ Coincidir con cualquier letra Unicode? ).

Por lo tanto, para eliminar todos los caracteres que no sean letras, puede hacer coincidir todas las letras y unir los resultados:

result = "".join(re.findall(r'[^\W\d_]', text))

O elimine todos los caracteres que no coincidan con [^\W\d_]:

result = re.sub(r'([^\W\d_])|.', r'\1', text, re.DOTALL)

Vea la demostración de expresiones regulares en línea . Sin embargo , es posible que obtenga resultados inconsistentes en varias versiones de Python porque el estándar Unicode está evolucionando y el conjunto de caracteres que coincidan \wdependerá de la versión de Python. regexSe recomienda encarecidamente utilizar la biblioteca PyPi para obtener resultados consistentes.

Wiktor Stribiżew
fuente