Eliminar todos los caracteres no numéricos de la cadena en Python

Respuestas:

267
>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
Ned Batchelder
fuente
90
eso podría ser re.sub (r "\ D", "", "sdkjh987978asd098as0980a98sd")
newacct
3
y eso podría ser: desde re import sub
James Koss
90

No estoy seguro si esta es la forma más eficiente, pero:

>>> ''.join(c for c in "abc123def456" if c.isdigit())
'123456'

La ''.joinparte significa combinar todos los caracteres resultantes juntos sin ningún carácter intermedio. Luego, el resto es una comprensión de la lista, donde (como probablemente puedas adivinar) solo tomamos las partes de la cadena que coinciden con la condición isdigit.

Mark Rushakoff
fuente
1
Eso hace lo contrario. Creo que te refieres a "no c.isdigit ()"
Ryan R. Rosario
77
Eliminar todos los no numéricos == mantener solo numéricos.
Mark Rushakoff
10
Me gusta que este enfoque no requiera tirar de re, para esta función simple.
triunenature
Tenga en cuenta que, a diferencia de las implementaciones que usan str.translate, esta solución funciona tanto en python 2.7 como en 3.4. ¡Gracias!
Alex
1
Prefiero esta alternativa Usar una expresión regular me parece excesivo.
alfredocambera el
18

Esto debería funcionar para cadenas y objetos unicode en Python2, y tanto cadenas como bytes en Python3:

# python <3.0
def only_numerics(seq):
    return filter(type(seq).isdigit, seq)

# python ≥3.0
def only_numerics(seq):
    seq_type= type(seq)
    return seq_type().join(filter(seq_type.isdigit, seq))
tzot
fuente
9

Solo para agregar otra opción a la mezcla, hay varias constantes útiles dentro del stringmódulo. Si bien son más útiles en otros casos, se pueden usar aquí.

>>> from string import digits
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'

Hay varias constantes en el módulo, que incluyen:

  • ascii_letters (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • hexdigits (0123456789abcdefABCDEF)

Si está utilizando estas constantes en gran medida, puede valer la pena convertirlas en a frozenset. Eso permite búsquedas O (1), en lugar de O (n), donde n es la longitud de la constante para las cadenas originales.

>>> digits = frozenset(digits)
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'
Tim McNamara
fuente
'' .join (c para c en "abc123def456" si c.isdigit ()) funciona en mi python 3.4
Eino Mäkitalo
7

@Ned Batchelder y @newacct dieron la respuesta correcta, pero ...

Por si acaso si tiene una coma (,) decimal (.) En su cadena:

import re
re.sub("[^\d\.]", "", "$1,999,888.77")
'1999888.77'
kennyut
fuente
5

El enfoque más rápido, si necesita realizar más de una o dos de estas operaciones de eliminación (¡o incluso solo una, pero en una cadena muy larga! -), es confiar en el translatemétodo de cadenas, a pesar de que necesita alguna preparación:

>>> import string
>>> allchars = ''.join(chr(i) for i in xrange(256))
>>> identity = string.maketrans('', '')
>>> nondigits = allchars.translate(identity, string.digits)
>>> s = 'abc123def456'
>>> s.translate(identity, nondigits)
'123456'

El translatemétodo es diferente, y tal vez un poco más simple de usar, en cadenas Unicode que en cadenas de bytes, por cierto:

>>> unondig = dict.fromkeys(xrange(65536))
>>> for x in string.digits: del unondig[ord(x)]
... 
>>> s = u'abc123def456'
>>> s.translate(unondig)
u'123456'

Es posible que desee utilizar una clase de mapeo en lugar de un dict real, especialmente si su cadena Unicode puede contener caracteres con valores ord muy altos (eso haría que el dict sea excesivamente grande ;-). Por ejemplo:

>>> class keeponly(object):
...   def __init__(self, keep): 
...     self.keep = set(ord(c) for c in keep)
...   def __getitem__(self, key):
...     if key in self.keep:
...       return key
...     return None
... 
>>> s.translate(keeponly(string.digits))
u'123456'
>>> 
Alex Martelli
fuente
2
(1) No codifique números mágicos; s / 65536 / sys.maxunicode / (2) El dict es incondicionalmente "excesivamente grande" porque la entrada "potencialmente" puede contener (sys.maxunicode - number_of_non_numeric_chars)entradas. (3) considere si string.digits puede no ser suficiente, lo que lleva a la necesidad de abrir el módulo unicodedata (4) considere re.sub (r '(? U) \ D +', u '', texto) por simplicidad y potencial velocidad.
John Machin
2

Muchas respuestas correctas, pero en caso de que lo desee en un flotador, directamente, sin usar expresiones regulares:

x= '$123.45M'

float(''.join(c for c in x if (c.isdigit() or c =='.'))

123,45

Puede cambiar el punto de una coma según sus necesidades.

cambie esto si sabe que su número es un entero

x='$1123'    
int(''.join(c for c in x if c.isdigit())

1123

Alberto Ibarra
fuente