web-dev-qa-db-fra.com

Supprimer les caractères sauf les chiffres de la chaîne en utilisant Python?

Comment puis-je supprimer tous les caractères sauf les numéros de chaîne?

116
Jan Tojnar

Dans Python 2. *, l'approche de loin la plus rapide est la méthode .translate:

>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>> 

string.maketrans Crée une table de traduction (une chaîne de longueur 256) qui, dans ce cas, est identique à ''.join(chr(x) for x in range(256)) (juste plus rapide à créer ;-). .translate Applique la table de traduction (ce qui n'est pas pertinent ici car all signifie essentiellement identité) ET supprime les caractères présents dans le deuxième argument - la partie clé.

.translate Fonctionne très différemment sur les chaînes Unicode (et les chaînes dans Python 3 - I do souhaite que des questions soient spécifiées quelle version majeure de Python est d’intérêt!) - pas aussi simple, pas aussi rapide, bien que toujours utilisable.

Retour à 2. *, la différence de performances est impressionnante ...:

$ 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

Accélérer les choses 7 à 8 fois n’est guère une arachide, la méthode translate vaut donc la peine d’être connue et utilisée. L'autre approche populaire non-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

50% plus lent que RE, l’approche .translate le bat donc de plus d’un ordre de grandeur.

Dans Python 3, ou pour Unicode, vous devez transmettre à .translate Un mappage (avec des ordinaux, pas de caractères directement, comme clé) qui renvoie None pour ce que vous voulez. effacer. Voici un moyen pratique d’exprimer cela en supprimant "tout sauf" quelques caractères:

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)

émet également '1233344554552'. Cependant, en mettant ceci dans xx.py nous avons ...:

$ 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

... ce qui montre que l'avantage de performance disparaît pour ce type de tâches de "suppression" et devient une diminution de performance.

105
Alex Martelli

Utilisation re.sub, ainsi:

>>> import re
>>> re.sub("\D", "", "aas30dsa20")
'3020'

\D correspond à tout caractère non numérique, le code ci-dessus remplace donc essentiellement chaque caractère non numérique de la chaîne vide.

Ou vous pouvez utiliser filter, comme suit (dans Python 2k):

>>> filter(lambda x: x.isdigit(), "aas30dsa20")
'3020'

Depuis in Python 3k, filter renvoie un itérateur au lieu d'un list, vous pouvez utiliser ce qui suit:

>>> ''.join(filter(lambda x: x.isdigit(), "aas30dsa20"))
'3020'
166
João Silva
s=''.join(i for i in s if i.isdigit())

Une autre variante de générateur.

58
f0b0s

Vous pouvez utiliser le filtre:

filter(lambda x: x.isdigit(), "dasdasd2313dsa")

Sur python3.0 vous devez rejoindre ceci (un peu moche :()

''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
16
freiksenet

dans le sens de la réponse de bayer:

''.join(i for i in s if i.isdigit())
11
SilentGhost

Vous pouvez facilement le faire en utilisant Regex

>>> import re
>>> re.sub("\D","","£70,000")
70000
10
Aminah Nuraini
x.translate(None, string.digits)

supprimera tous les chiffres de la chaîne. Pour supprimer des lettres et conserver les chiffres, procédez comme suit:

x.translate(None, string.letters)
7
Terje Molnes

L'op mentionne dans les commentaires qu'il veut conserver la décimale. Cela peut être fait avec la méthode re.sub (selon la deuxième réponse et la meilleure réponse à mon humble avis) en listant explicitement les caractères à conserver, par exemple.

>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
5
technicalbloke

Une version rapide pour 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)

Voici une comparaison de performance 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

C'est donc un peu plus de 3 fois plus rapide que regex, pour moi. C'est aussi plus rapide que class Del ci-dessus, car defaultdict effectue toutes ses recherches en C plutôt qu'en Python (lent). Voici cette version sur mon même système, à titre de comparaison.

$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
4
rescdsk

Moche mais ça marche:

>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
2
Gant
$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100 000 boucles, meilleur de 3: 2,48 usec par boucle

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100 000 boucles, le meilleur des 3: 2,02 utilisateurs par boucle

$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100 000 boucles, meilleur de 3: 2,37 usec par boucle

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100 000 boucles, le meilleur de 3: 1,97 usec par boucle

J'avais observé que rejoindre est plus rapide que sous.

1
AnilReddy

Utilisez une expression génératrice:

>>> s = "foo200bar"
>>> new_s = "".join(i for i in s if i in "0123456789")
1
bayer

Vous pouvez lire chaque personnage. S'il s'agit d'un chiffre, incluez-le dans la réponse. La str.isdigit()méthode permet de savoir si un caractère est numérique.

your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
1
yoelvis

Pas un one liner mais très simple:

buffer = ""
some_str = "aas30dsa20"

for char in some_str:
    if not char.isdigit():
        buffer += char

print( buffer )
0
Josh

J'ai utilisé ça. 'letters' Devrait contenir toutes les lettres dont vous voulez vous débarrasser:

Output = Input.translate({ord(i): None for i in 'letters'}))

Exemple:

Input = "I would like 20 dollars for that suit" Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'})) print(Output)

Sortie: 20

0
Gustav