Removendo todos os caracteres não numéricos da string no Python

Respostas:

267
>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
Ned Batchelder
fonte
89
que poderia ser re.sub (r "\ D", "", "sdkjh987978asd098as0980a98sd")
newacct 08/08/09
2
e que poderia ser: de sub importação re
James Koss
89

Não tenho certeza se essa é a maneira mais eficiente, mas:

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

A ''.joinparte significa combinar todos os caracteres resultantes sem nenhum caractere intermediário. Em seguida, o restante é uma lista de compreensão, onde (como você provavelmente pode imaginar) só pegamos as partes da string que correspondem à condição isdigit.

Mark Rushakoff
fonte
1
Isso faz o contrário. Eu acho que você quer dizer "não c.isdigit ()"
Ryan R. Rosário
7
Remova todos os não-numéricos == mantenha apenas numéricos.
Mark Rushakoff 08/08/09
10
Gosto que essa abordagem não exija re, para essa função simples.
Triunenature 25/05
Observe que, diferentemente das implementações usando str.translate, esta solução funciona no python 2.7 e 3.4. Obrigado!
Alex
1
Eu prefiro essa alternativa. Usar um regex parece um exagero para mim.
Alfredocambera
18

Isso deve funcionar para as seqüências de caracteres e os objetos unicode no Python2, e as seqüências de caracteres e bytes no 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
fonte
9

Apenas para adicionar outra opção à mistura, existem várias constantes úteis dentro do stringmódulo. Embora mais úteis em outros casos, eles podem ser usados ​​aqui.

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

Existem várias constantes no módulo, incluindo:

  • ascii_letters (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • hexdigits (0123456789abcdefABCDEF)

Se você estiver usando essas constantes intensamente, pode valer a pena cobri-las para a frozenset. Isso permite pesquisas O (1), em vez de O (n), onde n é o comprimento da constante para as seqüências originais.

>>> digits = frozenset(digits)
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'
Tim McNamara
fonte
'' .join (c para c em "abc123def456" se c.isdigit ()) funciona no meu python 3.4
Eino Mäkitalo 14/02/16
7

@Ned Batchelder e @newacct forneceram a resposta certa, mas ...

Caso você tenha vírgula (,) decimal (.) Na sua string:

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

A abordagem mais rápida, se você precisar executar mais do que apenas uma ou duas dessas operações de remoção (ou mesmo apenas uma, mas em uma sequência muito longa! -), é contar com o translatemétodo de sequências de caracteres, mesmo que precise de alguma preparação:

>>> 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'

O translatemétodo é diferente, e talvez um pouco mais simples, mais simples de usar, nas cadeias Unicode do que nas cadeias de bytes, btw:

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

Você pode querer usar uma classe de mapeamento em vez de um ditado real, especialmente se a sequência Unicode puder conter caracteres com valores ord muito altos (isso tornaria o ditado excessivamente grande ;-). Por exemplo:

>>> 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
fonte
2
(1) Não codifique números mágicos; s / 65536 / sys.maxunicode / (2) O ditado é incondicionalmente "excessivamente grande" porque a entrada "pode ​​potencialmente" conter (sys.maxunicode - number_of_non_numeric_chars)entradas. (3) considere se string.digits pode não ser suficiente, levando à necessidade de abrir o módulo unicodedata (4) considere re.sub (r '(? U) \ D +', u '', texto) por simplicidade e potencial Rapidez.
31720 John Machin
2

Muitas respostas certas, mas no caso de você querer isso diretamente, sem usar regex:

x= '$123.45M'

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

123,45

Você pode alterar o ponto da vírgula, dependendo de suas necessidades.

mude para isso se você souber que seu número é um número inteiro

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

1123

Alberto Ibarra
fonte