Suppression de tous les caractères non numériques de la chaîne en Python

Réponses:

267
>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
Ned Batchelder
la source
90
cela pourrait être re.sub (r "\ D", "", "sdkjh987978asd098as0980a98sd")
newacct
3
et cela pourrait être: from re import sub
James Koss
90

Je ne sais pas si c'est le moyen le plus efficace, mais:

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

La ''.joinpartie signifie combiner tous les caractères résultants ensemble sans aucun caractère entre les deux. Ensuite, le reste est une compréhension de liste, où (comme vous pouvez probablement le deviner) nous ne prenons que les parties de la chaîne qui correspondent à la condition isdigit.

Mark Rushakoff
la source
1
Cela fait le contraire. Je pense que vous voulez dire "not c.isdigit ()"
Ryan R. Rosario
7
Supprimer tous les non-numériques == ne conserver que les chiffres.
Mark Rushakoff
10
J'aime le fait que cette approche ne nécessite pas de tirer en re, pour cette fonction simple.
triunenature
Notez que contrairement aux implémentations utilisant str.translate, cette solution fonctionne à la fois en python 2.7 et 3.4. Je vous remercie!
Alex
1
Je préfère cette alternative. Utiliser une regex me semble exagéré.
alfredocambera
18

Cela devrait fonctionner à la fois pour les chaînes et les objets Unicode dans Python2, et pour les chaînes et les octets dans 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
la source
9

Juste pour ajouter une autre option au mix, il y a plusieurs constantes utiles dans le stringmodule. Bien que plus utiles dans d'autres cas, ils peuvent être utilisés ici.

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

Il existe plusieurs constantes dans le module, notamment:

  • ascii_letters (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • hexdigits (0123456789abcdefABCDEF)

Si vous utilisez beaucoup ces constantes, il peut être intéressant de les convertir en un fichier frozenset. Cela permet les recherches O (1), plutôt que O (n), où n est la longueur de la constante pour les chaînes d'origine.

>>> digits = frozenset(digits)
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'
Tim McNamara
la source
'' .join (c pour c dans "abc123def456" si c.isdigit ()) fonctionne dans mon python 3.4
Eino Mäkitalo
7

@Ned Batchelder et @newacct ont fourni la bonne réponse, mais ...

Juste au cas où vous avez une virgule (,) décimal (.) Dans votre chaîne:

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

L'approche la plus rapide, si vous devez effectuer plus d'une ou deux opérations de suppression de ce type (ou même une seule, mais sur une très longue chaîne! -), est de vous fier à la translateméthode des chaînes, même si elle nécessite un peu de préparation:

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

La translateméthode est différente, et peut-être un peu plus simple à utiliser, sur les chaînes Unicode que sur les chaînes d'octets, btw:

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

Vous voudrez peut-être utiliser une classe de mappage plutôt qu'un dict réel, surtout si votre chaîne Unicode peut potentiellement contenir des caractères avec des valeurs ord très élevées (cela rendrait le dict excessivement grand ;-). Par exemple:

>>> 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
la source
2
(1) Ne codez pas en dur les nombres magiques; s / 65536 / sys.maxunicode / (2) Le dict est inconditionnellement «excessivement grand» car l'entrée «peut potentiellement» contenir des (sys.maxunicode - number_of_non_numeric_chars)entrées. (3) considérer si string.digits peut ne pas être suffisant conduisant à la nécessité d'ouvrir le module unicodedata (4) considérer re.sub (r '(? U) \ D +', u '', text) pour la simplicité et le potentiel la vitesse.
John Machin
2

Beaucoup de bonnes réponses mais au cas où vous le voudriez dans un float, directement, sans utiliser de regex:

x= '$123.45M'

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

123,45

Vous pouvez changer le point d'une virgule en fonction de vos besoins.

changez pour cela si vous savez que votre nombre est un entier

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

1123

Alberto Ibarra
la source