Como posso remover todos os caracteres, exceto números da string?
Como posso remover todos os caracteres, exceto números da string?
Respostas:
No Python 2. *, de longe a abordagem mais rápida é o .translate
método:
>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>>
string.maketrans
cria uma tabela de conversão (uma string de comprimento 256) que, neste caso, é a mesma que ''.join(chr(x) for x in range(256))
(apenas mais rápida de fazer ;-). .translate
aplica a tabela de conversão (que aqui é irrelevante, pois all
significa essencialmente identidade) E exclui os caracteres presentes no segundo argumento - a parte principal.
.translate
funciona de forma muito diferente em cadeias de caracteres Unicode (e strings em Python 3 - I fazer perguntas desejo especificado que grande-lançamento do Python é de interesse!) - não é tão simples, não é bem isso rápido, embora ainda bastante utilizável.
De volta a 2. *, a diferença de desempenho é impressionante ...:
$ 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 as coisas em 7-8 vezes dificilmente é um amendoim, portanto translate
vale a pena conhecer e usar o método. A outra abordagem popular não-ER ...:
$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop
é 50% mais lento que ER, então a .translate
abordagem supera-a em uma ordem de magnitude.
No Python 3 ou no Unicode, você precisa passar .translate
um mapeamento (com ordinais, não caracteres diretamente, como chaves) que retorna None
para o que você deseja excluir. Aqui está uma maneira conveniente de expressar isso para excluir "tudo menos" alguns 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)
também emite '1233344554552'
. No entanto, colocando isso no xx.py, temos ...:
$ 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 mostra que a vantagem de desempenho desaparece para esse tipo de "exclusão" de tarefas e se torna uma diminuição de desempenho.
x.translate(None, string.digits)
na verdade resulta em 'aaabbbbbb'
, que é o oposto do que se destina.
all
builtin ... não tenho certeza sobre isso!
Use re.sub
, assim:
>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'
\D
corresponde a qualquer caractere que não seja um dígito, portanto, o código acima substitui essencialmente todos os caracteres que não são dígitos da string vazia.
Ou você pode usar filter
, assim (no Python 2):
>>> filter(str.isdigit, 'aas30dsa20')
'3020'
Como no Python 3, filter
retorna um iterador em vez de a list
, você pode usar o seguinte:
>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'
isdigit
, com gerador isdigt
está a meio caminho entre eles
r
para string bruta:re.sub(r"\D+", "", "aas30dsa20")
s=''.join(i for i in s if i.isdigit())
Outra variante do gerador.
Você pode usar o filtro:
filter(lambda x: x.isdigit(), "dasdasd2313dsa")
No python3.0 você tem que se juntar a isso (meio feio :()
''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
str
para list
garantir que ele funcione em py2 e py3:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
na linha da resposta da bayer:
''.join(i for i in s if i.isdigit())
-
não é um dígito.
x.translate(None, string.digits)
excluirá todos os dígitos da string. Para excluir letras e manter os dígitos, faça o seguinte:
x.translate(None, string.letters)
TypeError
: translate () leva exatamente um argumento (2 dados). Por que essa pergunta foi votada em seu estado atual é bastante frustrante.
A opção menciona nos comentários que ele deseja manter a casa decimal. Isso pode ser feito com o método re.sub (conforme a segunda e melhor resposta do IMHO) listando explicitamente os caracteres a serem mantidos, por exemplo
>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Uma versão 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)
Aqui está uma comparação de desempenho versus 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
Então, é um pouco mais de três vezes mais rápido que o regex, para mim. Também é mais rápido do que o class Del
anterior, porque defaultdict
faz todas as suas pesquisas em C, em vez de (lento) Python. Aqui está essa versão no meu mesmo sistema, para comparação.
$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
Feio, mas funciona:
>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
list(s)
?
filter(lambda x: x.isdigit(), s)
funcionou bem para mim. ... ah, é porque eu estou usando o Python 2.7.
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, o melhor de 3: 2,48 usec por loop
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 loops, o melhor de 3: 2,02 usec por loop
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, o melhor de 3: 2,37 usec por loop
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 loops, o melhor de 3: 1,97 usec por loop
Eu tinha observado que a junção é mais rápida que a sub.
Você pode ler cada personagem. Se for dígito, inclua-o na resposta. O str.isdigit()
método é uma maneira de saber se um caractere é um dígito.
your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
Eu usei isso. 'letters'
deve conter todas as letras das quais você deseja se livrar:
Output = Input.translate({ord(i): None for i in 'letters'}))
Exemplo:
Input = "I would like 20 dollars for that suit"
Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'}))
print(Output)
Resultado:
20