Vérifier si une chaîne contient un nombre


214

La plupart des questions que j'ai trouvées sont biaisées sur le fait qu'ils recherchent des lettres dans leurs nombres, alors que je recherche des nombres dans ce que j'aimerais être une chaîne infinie. Je dois entrer une chaîne et vérifier si elle contient des nombres et si elle la rejette.

La fonction isdigit()ne renvoie que Truesi TOUS les caractères sont des nombres. Je veux juste voir si l'utilisateur a entré un nombre donc une phrase comme "I own 1 dog"ou quelque chose.

Des idées?


Réponses:


321

Vous pouvez utiliser la anyfonction, avec la str.isdigitfonction, comme ceci

>>> def hasNumbers(inputString):
...     return any(char.isdigit() for char in inputString)
... 
>>> hasNumbers("I own 1 dog")
True
>>> hasNumbers("I own no dog")
False

Vous pouvez également utiliser une expression régulière, comme celle-ci

>>> import re
>>> def hasNumbers(inputString):
...     return bool(re.search(r'\d', inputString))
... 
>>> hasNumbers("I own 1 dog")
True
>>> hasNumbers("I own no dog")
False

Et les nombres négatifs?
Ray

@Ray Then the RegEx peut être étendu comme çar'-?\d+'
thefourtheye

17
Est-ce que l'expression régulière d'origine ne détecte pas les nombres négatifs de toute façon?
confused00

1
@ confused00 Non, \dne correspondra qu'à un seul chiffre dans la plage 0à 9.
thefourtheye

10
@thefourtheye: -1 est toujours un chiffre. C'est un tiret, suivi du chiffre '1'
user3183018

53

Vous pouvez utiliser une combinaison de anyet str.isdigit:

def num_there(s):
    return any(i.isdigit() for i in s)

La fonction retournera Truesi un chiffre existe dans la chaîne, sinon False.

Démo:

>>> king = 'I shall have 3 cakes'
>>> num_there(king)
True
>>> servant = 'I do not have any cakes'
>>> num_there(servant)
False

Pas besoin de créer une liste temporaire, vous pouvez utiliser une expression de générateur à la place en supprimant simplement ces crochets.
Matteo Italia

Ah oui, je viens de réaliser que cela anyaccepte les expressions génératrices.
aIKid


28

https://docs.python.org/2/library/re.html

Vous devriez mieux utiliser une expression régulière. C'est beaucoup plus rapide.

import re

def f1(string):
    return any(i.isdigit() for i in string)


def f2(string):
    return re.search('\d', string)


# if you compile the regex string first, it's even faster
RE_D = re.compile('\d')
def f3(string):
    return RE_D.search(string)

# Output from iPython
# In [18]: %timeit  f1('assdfgag123')
# 1000000 loops, best of 3: 1.18 µs per loop

# In [19]: %timeit  f2('assdfgag123')
# 1000000 loops, best of 3: 923 ns per loop

# In [20]: %timeit  f3('assdfgag123')
# 1000000 loops, best of 3: 384 ns per loop

f3 ne renvoie rien
pyd

Cela signifie qu'il n'y a pas de correspondance, il revientNone
zyxue

RE_D = re.compile ('\ d') def has_digits (string): res = RE_D.search (string) return res is not None
Raul

9

Vous pouvez appliquer la fonction isdigit () sur chaque caractère de la chaîne. Ou vous pouvez utiliser des expressions régulières.

J'ai également trouvé Comment trouver un nombre dans une chaîne en Python? avec des moyens très appropriés pour renvoyer des nombres. La solution ci-dessous provient de la réponse à cette question.

number = re.search(r'\d+', yourString).group()

Alternativement:

number = filter(str.isdigit, yourString)

Pour plus d'informations, consultez le docu regex: http://docs.python.org/2/library/re.html

Edit: Cela renvoie les nombres réels, pas une valeur booléenne, donc les réponses ci-dessus sont plus correctes pour votre cas

La première méthode renverra le premier chiffre et les chiffres consécutifs suivants. Ainsi 1.56 sera retourné comme 1. 10.000 sera retourné comme 10. 0207-100-1000 sera retourné comme 0207.

La deuxième méthode ne fonctionne pas.

Pour extraire tous les chiffres, points et virgules, et ne pas perdre de chiffres non consécutifs, utilisez:

re.sub('[^\d.,]' , '', yourString)

3

Vous pouvez accomplir cela comme suit:

if a_string.isdigit(): do_this() else: do_that()

https://docs.python.org/2/library/stdtypes.html#str.isdigit

Utiliser .isdigit()signifie également ne pas avoir à recourir à la gestion des exceptions (try / except) dans les cas où vous avez besoin d'utiliser la compréhension de liste (try / except n'est pas possible dans une compréhension de liste).


3

Vous pouvez utiliser la méthode NLTK pour cela.

Cela trouvera à la fois '1' et 'One' dans le texte:

import nltk 

def existence_of_numeric_data(text):
    text=nltk.word_tokenize(text)
    pos = nltk.pos_tag(text)
    count = 0
    for i in range(len(pos)):
        word , pos_tag = pos[i]
        if pos_tag == 'CD':
            return True
    return False

existence_of_numeric_data('We are going out. Just five you and me.')

2

Vous pouvez utiliser range with count pour vérifier combien de fois un nombre apparaît dans la chaîne en le comparant à la plage:

def count_digit(a):
    sum = 0
    for i in range(10):
        sum += a.count(str(i))
    return sum

ans = count_digit("apple3rh5")
print(ans)

#This print 2

2

Je suis surpris que personne n'ait mentionné cette combinaison de anyet map:

def contains_digit(s):
    isdigit = str.isdigit
    return any(map(isdigit,s))

en python 3, c'est probablement le plus rapide là-bas (sauf peut-être pour les regex) car il ne contient aucune boucle (et l'aliaser la fonction évite de la rechercher str).

N'utilisez pas cela dans python 2 comme mapretourne a list, ce qui rompt le anycourt-circuit


2

anyet ordpeuvent être combinés pour atteindre l'objectif indiqué ci-dessous.

>>> def hasDigits(s):
...     return any( 48 <= ord(char) <= 57 for char in s)
...
>>> hasDigits('as1')
True
>>> hasDigits('as')
False
>>> hasDigits('as9')
True
>>> hasDigits('as_')
False
>>> hasDigits('1as')
True
>>>

Quelques points sur cette implémentation.

  1. any est mieux car il fonctionne comme une expression de court-circuit en langage C et retournera le résultat dès qu'il pourra être déterminé, c'est-à-dire en cas de chaîne 'a1bbbbbbc' 'b's et' c's ne seront même pas comparés.

  2. ordest mieux car il offre plus de flexibilité, comme les numéros de contrôle entre «0» et «5» ou toute autre plage. Par exemple, si vous deviez écrire un validateur pour la représentation hexadécimale des nombres, vous voudriez que la chaîne ait des alphabets dans la plage «A» à «F» uniquement.


2

Et celui-là?

import string

def containsNumber(line):
    res = False
    try:
        for val in line.split():
            if (float(val.strip(string.punctuation))):
                res = True
                break
    except ValueError:
        pass
    return res

containsNumber('234.12 a22') # returns True
containsNumber('234.12L a22') # returns False
containsNumber('234.12, a22') # returns True

1
Veuillez ne pas simplement lancer votre code source ici. Soyez gentil et essayez de donner une belle description à votre réponse, afin que les autres l'aiment et la votent. Voir: Comment écrire une bonne réponse?
sɐunıɔ ןɐ qɐp

2

Je vais rendre la réponse @zyxue un peu plus explicite:

RE_D = re.compile('\d')

def has_digits(string):
    res = RE_D.search(string)
    return res is not None

has_digits('asdf1')
Out: True

has_digits('asdf')
Out: False

qui est la solution avec le benchmark le plus rapide parmi les solutions proposées par @zyxue sur la réponse.


1

Un moyen plus simple de résoudre est de

s = '1dfss3sw235fsf7s'
count = 0
temp = list(s)
for item in temp:
    if(item.isdigit()):
        count = count + 1
    else:
        pass
print count

1
Bienvenue dans Stack Overflow! Veuillez ne pas simplement lancer votre code source ici. Soyez gentil et essayez de donner une belle description à votre réponse, afin que les autres l'aiment et la votent. Voir: Comment écrire une bonne réponse?
sɐunıɔ ןɐ qɐp

1
import string
import random
n = 10

p = ''

while (string.ascii_uppercase not in p) and (string.ascii_lowercase not in p) and (string.digits not in p):
    for _ in range(n):
        state = random.randint(0, 2)
        if state == 0:
            p = p + chr(random.randint(97, 122))
        elif state == 1:
            p = p + chr(random.randint(65, 90))
        else:
            p = p + str(random.randint(0, 9))
    break
print(p)

Ce code génère une séquence de taille n qui contient au moins une majuscule, une minuscule et un chiffre. En utilisant la boucle while, nous avons garanti cet événement.


Veuillez ajouter une explication à votre réponse
Mastisa

1
alp_num = [x for x in string.split() if x.isalnum() and re.search(r'\d',x) and 
re.search(r'[a-z]',x)]

print(alp_num)

Cela renvoie toute la chaîne qui contient à la fois des alphabets et des nombres. isalpha () renvoie la chaîne avec tous les chiffres ou tous les caractères.


1

Ce n'est probablement pas la meilleure approche en Python, mais en tant que Haskeller, cette approche lambda / map me semblait parfaitement logique et est très courte:

anydigit = lambda x: any(map(str.isdigit, x))

N'a pas besoin d'être nommé bien sûr. Nommé il pourrait être utilisé comme anydigit("abc123"), ce qui ressemble à ce que je cherchais!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.