Comment puis-je supprimer tous les caractères sauf les numéros de chaîne?
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.
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'
s=''.join(i for i in s if i.isdigit())
Une autre variante de générateur.
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"))
dans le sens de la réponse de bayer:
''.join(i for i in s if i.isdigit())
Vous pouvez facilement le faire en utilisant Regex
>>> import re
>>> re.sub("\D","","£70,000")
70000
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)
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'
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
Moche mais ça marche:
>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
$ 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.
Utilisez une expression génératrice:
>>> s = "foo200bar"
>>> new_s = "".join(i for i in s if i in "0123456789")
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'
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 )
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