¿Cómo puedo eliminar todos los caracteres excepto los números de la cadena?
¿Cómo puedo eliminar todos los caracteres excepto los números de la cadena?
Respuestas:
En Python 2. *, con mucho, el enfoque más rápido es el .translate
método:
>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>>
string.maketrans
crea una tabla de traducción (una cadena de longitud 256) que en este caso es la misma que ''.join(chr(x) for x in range(256))
(simplemente más rápida de hacer ;-). .translate
aplica la tabla de traducción (que aquí es irrelevante ya queall
esencialmente significa identidad) Y elimina los caracteres presentes en el segundo argumento, la parte clave.
.translate
funciona de manera muy diferente en cadenas Unicode (y cadenas en Python 3 - lo hago preguntas deseos especifican los cuales importante de liberación de Python es de interés!) - no es este sencillo, no es tan rápido, aunque todavía bastante usable.
Volviendo a 2. *, la diferencia de rendimiento es impresionante ...:
$ python -mtimeit -s'import string; all=string.maketrans("", ""); nodig=all.translate(all, string.digits); x="aaa12333bb445bb54b5b52"' 'x.translate(all, nodig)'
1000000 loops, best of 3: 1.04 usec per loop
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 7.9 usec per loop
Acelerar las cosas entre 7 y 8 veces no es nada fácil, por lo translate
que vale la pena conocer y utilizar el método. El otro enfoque popular no RE ...:
$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop
es 50% más lento que RE, por lo que el .translate
enfoque lo supera en un orden de magnitud.
En Python 3, o para Unicode, debe pasar .translate
una asignación (con ordinales, no caracteres directamente, como teclas) que devuelve None
lo que desea eliminar. Aquí hay una manera conveniente de expresar esto para eliminar "todo menos" algunos caracteres:
import string
class Del:
def __init__(self, keep=string.digits):
self.comp = dict((ord(c),c) for c in keep)
def __getitem__(self, k):
return self.comp.get(k)
DD = Del()
x='aaa12333bb445bb54b5b52'
x.translate(DD)
También emite '1233344554552'
. Sin embargo, poniendo esto en xx.py tenemos ...:
$ python3.1 -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 8.43 usec per loop
$ python3.1 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
10000 loops, best of 3: 24.3 usec per loop
... que muestra que la ventaja de rendimiento desaparece, para este tipo de tareas de "eliminación", y se convierte en una disminución del rendimiento.
x.translate(None, string.digits)
en realidad da como resultado 'aaabbbbbb'
, que es lo contrario de lo que se pretende.
all
construcción ... no estoy seguro de eso!
Uso re.sub
, así:
>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'
\D
coincide con cualquier carácter que no sea un dígito, por lo tanto, el código anterior reemplaza esencialmente cada carácter que no sea un dígito para la cadena vacía.
O puede usar filter
, así (en Python 2):
>>> filter(str.isdigit, 'aas30dsa20')
'3020'
Dado que en Python 3, filter
devuelve un iterador en lugar de a list
, puede usar lo siguiente en su lugar:
>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'
isdigit
, generador con isdigt
está a medio camino entre ellos
r
para cadena cruda:re.sub(r"\D+", "", "aas30dsa20")
Puedes usar filter:
filter(lambda x: x.isdigit(), "dasdasd2313dsa")
En python3.0 tienes que unirte a esto (un poco feo :()
''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
str
para list
asegurarse de que funciona tanto en py2 como en py3:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
en la línea de la respuesta de bayer:
''.join(i for i in s if i.isdigit())
-
no es un dígito.
x.translate(None, string.digits)
eliminará todos los dígitos de la cadena. Para eliminar letras y conservar los dígitos, haga esto:
x.translate(None, string.letters)
TypeError
: translate () toma exactamente un argumento (2 dados). Por qué esta pregunta fue votada en su estado actual es bastante frustrante.
La opción menciona en los comentarios que quiere mantener el lugar decimal. Esto se puede hacer con el método re.sub (según el segundo y la mejor respuesta de la OMI) enumerando explícitamente los caracteres para mantener, por ejemplo
>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Una versión rápida para Python 3:
# xx3.py
from collections import defaultdict
import string
_NoneType = type(None)
def keeper(keep):
table = defaultdict(_NoneType)
table.update({ord(c): c for c in keep})
return table
digit_keeper = keeper(string.digits)
Aquí hay una comparación de rendimiento vs. regex:
$ python3.3 -mtimeit -s'import xx3; x="aaa12333bb445bb54b5b52"' 'x.translate(xx3.digit_keeper)'
1000000 loops, best of 3: 1.02 usec per loop
$ python3.3 -mtimeit -s'import re; r = re.compile(r"\D"); x="aaa12333bb445bb54b5b52"' 'r.sub("", x)'
100000 loops, best of 3: 3.43 usec per loop
Entonces, es un poco más de 3 veces más rápido que la expresión regular, para mí. También es más rápido que el class Del
anterior, porque defaultdict
realiza todas sus búsquedas en C, en lugar de Python (lento). Aquí está esa versión en mi mismo sistema, para comparar.
$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
Feo pero funciona:
>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
list(s)
?
filter(lambda x: x.isdigit(), s)
funcionó bien para mí ... oh, es porque estoy usando Python 2.7.
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 bucles, lo mejor de 3: 2,48 usec por bucle
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 bucles, lo mejor de 3: 2.02 usec por bucle
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 bucles, lo mejor de 3: 2.37 usec por bucle
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 bucles, lo mejor de 3: 1.97 usec por bucle
Había observado que join es más rápido que sub.
Puedes leer cada personaje. Si es un dígito, inclúyalo en la respuesta. El str.isdigit()
método es una forma de saber si un personaje es un dígito.
your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
Yo usé esto 'letters'
debe contener todas las letras de las que desea deshacerse:
Output = Input.translate({ord(i): None for i in 'letters'}))
Ejemplo:
Input = "I would like 20 dollars for that suit"
Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'}))
print(Output)
Salida:
20