Eliminar todos los caracteres especiales, signos de puntuación y espacios de la cadena

236

Necesito eliminar todos los caracteres especiales, signos de puntuación y espacios de una cadena para que solo tenga letras y números.

usuario664546
fuente

Respuestas:

351

Esto se puede hacer sin expresiones regulares:

>>> string = "Special $#! characters   spaces 888323"
>>> ''.join(e for e in string if e.isalnum())
'Specialcharactersspaces888323'

Puedes usar str.isalnum:

S.isalnum() -> bool

Return True if all characters in S are alphanumeric
and there is at least one character in S, False otherwise.

Si insiste en usar expresiones regulares, otras soluciones funcionarán bien. Sin embargo, tenga en cuenta que si se puede hacer sin usar una expresión regular, esa es la mejor manera de hacerlo.

usuario225312
fuente
77
¿Cuál es la razón por la que no se usa la expresión regular como regla general?
Chris Dutrow
@ChrisDutrow regex son más lentos que las funciones integradas de la cadena de Python
Diego Navarro
Esto solo funciona cuando la cadena está en unicode . De lo contrario, se queja de que el objeto 'str' no tiene el atributo 'isalnum' 'isnumeric' y así sucesivamente.
NeoJi
10
@DiegoNavarro, excepto que no es cierto, comparé las isalnum()versiones regex y regex, y la expresión regular es 50-75% más rápida
Francisco Couzo
2
Además: "Para cadenas de 8 bits, este método depende de la configuración regional". Por lo tanto, la alternativa regex es estrictamente mejor.
Antti Haapala
232

Aquí hay una expresión regular para que coincida con una cadena de caracteres que no son letras o números:

[^A-Za-z0-9]+

Aquí está el comando Python para hacer una sustitución de expresiones regulares:

re.sub('[^A-Za-z0-9]+', '', mystring)
Andy White
fuente
10
BESO: ¡Mantenlo simple, estúpido! Esto es más corto y mucho más fácil de leer que las soluciones que no son expresiones regulares y también puede ser más rápido. (Sin embargo, agregaría un +cuantificador para mejorar un poco su eficiencia.)
ridgerunner
1
esto también elimina los espacios entre palabras, "gran lugar" -> "gran lugar". ¿Cómo evitarlo?
Reihan_amn
55
@Reihan_amn Simplemente agregue un espacio a la expresión regular, para que se convierta en:[^A-Za-z0-9 ]+
ostroon
1
@ andy-white ¿puedes agregar el espacio a la expresión regular en la respuesta? El espacio no es un personaje especial ...
Ufos
3
Supongo que esto no funciona con caracteres modificados en otros idiomas, como á , ö , ñ , etc. ¿Estoy en lo cierto? Si es así, ¿cómo sería la expresión regular para ello?
HuLu ViCa
50

Camino más corto:

import re
cleanString = re.sub('\W+','', string )

Si desea espacios entre palabras y números, sustituya '' por ''

tuxErrante
fuente
3
Excepto que _ está en \ wy es un carácter especial en el contexto de esta pregunta.
kkurian
Depende del contexto: el guión bajo es muy útil para los nombres de archivo y otros identificadores, hasta el punto de que no lo trato como un carácter especial, sino más bien como un espacio desinfectado. Generalmente uso este método yo mismo.
Echelon
1
r'\W+'- ligeramente fuera de tema (y muy pedante) pero sugiero un hábito de que todos los patrones de expresiones regulares sean cadenas sin procesar
Bob Stein
2
Este procedimiento no trata el guión bajo (_) como un carácter especial.
Md. Sabbir Ahmed
30

Después de ver esto, estaba interesado en ampliar las respuestas proporcionadas descubriendo cuál se ejecuta en la menor cantidad de tiempo, así que revisé algunas de las respuestas propuestas con timeitdos de las cadenas de ejemplo:

  • string1 = 'Special $#! characters spaces 888323'
  • string2 = 'how much for the maple syrup? $20.99? That s ricidulous!!!'

Ejemplo 1

'.join(e for e in string if e.isalnum())

  • string1 - Resultado: 10.7061979771
  • string2 - Resultado: 7.78372597694

Ejemplo 2

import re re.sub('[^A-Za-z0-9]+', '', string)

  • string1 - Resultado: 7.10785102844
  • string2 - Resultado: 4.12814903259

Ejemplo 3

import re re.sub('\W+','', string)

  • string1 - Resultado: 3.11899876595
  • string2 - Resultado: 2.78014397621

Los resultados anteriores son un producto del resultado más bajo devuelto de un promedio de: repeat(3, 2000000)

El ejemplo 3 puede ser 3 veces más rápido que el ejemplo 1 .

mbeacom
fuente
@kkurian Si lees el comienzo de mi respuesta, esto es simplemente una comparación de las soluciones propuestas anteriormente. Es posible que desee comentar la respuesta original ... stackoverflow.com/a/25183802/2560922
mbeacom
Oh, ya veo a dónde vas con esto. ¡Hecho!
kkurian
1
Debe considerar el Ejemplo 3, cuando se trata de grandes corpus.
HARSH NILESH PATHAK
¡Válido! Gracias por notarlo.
mbeacom
¿puedes comparar mi respuesta''.join([*filter(str.isalnum, string)])
Grijesh Chauhan
22

Python 2. *

Creo que solo filter(str.isalnum, string)funciona

In [20]: filter(str.isalnum, 'string with special chars like !,#$% etcs.')
Out[20]: 'stringwithspecialcharslikeetcs'

Python 3. *

En Python3, la filter( )función devolvería un objeto itertable (en lugar de una cadena a diferencia de lo anterior). Uno tiene que unirse para obtener una cadena de itertable:

''.join(filter(str.isalnum, string)) 

o para pasar el listuso de combinación ( no estoy seguro pero puede ser un poco rápido )

''.join([*filter(str.isalnum, string)])

nota: desempaquetado [*args]válido desde Python> = 3.5

Grijesh Chauhan
fuente
44
@Alexey correcto, En python3 map, filtery reduce vuelve objeto itertable lugar. Todavía en Python3 + preferiré ''.join(filter(str.isalnum, string)) (o aprobar la lista en combinación ''.join([*filter(str.isalnum, string)])) sobre la respuesta aceptada.
Grijesh Chauhan
No estoy seguro de si ''.join(filter(str.isalnum, string))es una mejora filter(str.isalnum, string), al menos para leer. ¿Es esta realmente la forma Pythreenic (sí, puedes usar eso) para hacer esto?
TheProletariat
1
@TheProletariat El punto es simplementefilter(str.isalnum, string) no devolver la cadena en Python3 como filter( )en Python-3 devuelve el iterador en lugar del tipo de argumento a diferencia de Python-2. +
Grijesh Chauhan
@GrijeshChauhan, creo que deberías actualizar tu respuesta para incluir tus recomendaciones Python2 y Python3.
mwfearnley
18
#!/usr/bin/python
import re

strs = "how much for the maple syrup? $20.99? That's ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!]',r'',strs)
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)
print nestr

puedes agregar más caracteres especiales y eso será reemplazado por "no significa nada, es decir, serán eliminados.

pkm
fuente
16

A diferencia de lo que todos los demás usaban regex, trataría de excluir cada personaje que no sea lo que quiero, en lugar de enumerar explícitamente lo que no quiero.

Por ejemplo, si solo quiero caracteres de 'a a z' (mayúsculas y minúsculas) y números, excluiría todo lo demás:

import re
s = re.sub(r"[^a-zA-Z0-9]","",s)

Esto significa "sustituir cada carácter que no sea un número o un carácter en el rango 'a a z' o 'A a Z' con una cadena vacía".

De hecho, si inserta el carácter especial ^en el primer lugar de su expresión regular, obtendrá la negación.

Consejo adicional: si también necesita minúsculas el resultado, puede hacer que la expresión regular sea aún más rápida y fácil, siempre que no encuentre mayúsculas ahora.

import re
s = re.sub(r"[^a-z0-9]","",s.lower())
Andrea
fuente
9

Suponiendo que desea usar una expresión regular y desea / necesita un código 2.x compatible con Unicode que esté listo para 2to3:

>>> import re
>>> rx = re.compile(u'[\W_]+', re.UNICODE)
>>> data = u''.join(unichr(i) for i in range(256))
>>> rx.sub(u'', data)
u'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\xaa\xb2 [snip] \xfe\xff'
>>>
John Machin
fuente
7
s = re.sub(r"[-()\"#/@;:<>{}`+=~|.!?,]", "", s)
sneha
fuente
6

El enfoque más genérico es usar las 'categorías' de la tabla unicodedata que clasifica cada carácter. Por ejemplo, el siguiente código filtra solo los caracteres imprimibles según su categoría:

import unicodedata
# strip of crap characters (based on the Unicode database
# categorization:
# http://www.sql-und-xml.de/unicode-database/#kategorien

PRINTABLE = set(('Lu', 'Ll', 'Nd', 'Zs'))

def filter_non_printable(s):
    result = []
    ws_last = False
    for c in s:
        c = unicodedata.category(c) in PRINTABLE and c or u'#'
        result.append(c)
    return u''.join(result).replace(u'#', u' ')

Mire la URL dada arriba para todas las categorías relacionadas. Por supuesto, también puede filtrar por categorías de puntuación.

Andreas Jung
fuente
¿Qué pasa con el $al final de cada línea?
John Machin
Si se trata de copiar y pegar, ¿debería solucionarlo?
Olli
5

string.punctuation contiene los siguientes caracteres:

'! "# $% & \' () * +, -. / :; <=>? @ [\] ^ _` {|} ~ '

Puede usar las funciones de traducción y conversión para asignar signos de puntuación a valores vacíos (reemplazar)

import string

'This, is. A test!'.translate(str.maketrans('', '', string.punctuation))

Salida:

'This is A test'
Vlad Bezden
fuente
4

Usa traductor:

import string

def clean(instr):
    return instr.translate(None, string.punctuation + ' ')

Advertencia: solo funciona en cadenas ASCII.

jjmurre
fuente
¿Diferencia de versión? Me sale TypeError: translate() takes exactly one argument (2 given)con py3.4
matt wilkie
1
import re
my_string = """Strings are amongst the most popular data types in Python. We can create the strings by enclosing characters in quotes. Python treats single quotes the 

igual que las comillas dobles "" "

# if we need to count the word python that ends with or without ',' or '.' at end

count = 0
for i in text:
    if i.endswith("."):
        text[count] = re.sub("^([a-z]+)(.)?$", r"\1", i)
    count += 1
print("The count of Python : ", text.count("python"))
Vinay Kumar Kuresi
fuente
0
import re
abc = "askhnl#$%askdjalsdk"
ddd = abc.replace("#$%","")
print (ddd)

y verás tu resultado como

'askhnlaskdjalsdk

Dsw Wds
fuente
44
espera ... lo importaste repero nunca lo usaste. Sus replacecriterios solo funcionan para esta cadena específica. ¿Qué pasa si tu cuerda es abc = "askhnl#$%!askdjalsdk"? No creo que funcione en otra cosa que no sea el #$%patrón. Podría querer modificarlo
JChao
0

Eliminar signos de puntuación, números y caracteres especiales

Ejemplo:

ingrese la descripción de la imagen aquí

Código

combi['tidy_tweet'] = combi['tidy_tweet'].str.replace("[^a-zA-Z#]", " ") 

Resultado:- ingrese la descripción de la imagen aquí

Gracias :)

Harish Kumawat
fuente
0

Para otros idiomas como el alemán, español, danés, francés, etc., que contienen caracteres especiales (como el alemán "Umlaute", como ü, ä, ö) simplemente añadir estos a la cadena de búsqueda de expresiones regulares:

Ejemplo para alemán:

re.sub('[^A-ZÜÖÄa-z0-9]+', '', mystring)
petezurich
fuente