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?

Donnelly
la source
Solution: stackoverflow.com/a/64132078/8321339
Vishal Gupta

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
thefourtheye
la source
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
aIKid
la source
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
31

utilisation

str.isalpha () 

Réf: https://docs.python.org/2/library/stdtypes.html#str.isalpha

Renvoie true si tous les caractères de la chaîne sont alphabétiques et qu'il y a au moins un caractère, false sinon.

K246
la source
11
Il existe d'autres types de caractères que alphabétiques et numériques - par exemple, '_'.isalpha()est False.
lvc
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
zyxue
la source
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)
Haini
la source
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).

olisteadman
la source
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.')
Mahendra S. Chouhan
la source
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
pédestre
la source
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

Jean-François Fabre
la source
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.

ViFI
la source
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
aga
la source
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.

Raul
la source
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
Tempête De Neige
la source
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.

Mehran Attar
la source
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.

Sai ram
la source
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!

Oscar Sud
la source