323

Most of the questions I've found are biased on the fact they're looking for letters in their numbers, whereas I'm looking for numbers in what I'd like to be a numberless string. I need to enter a string and check to see if it contains any numbers and if it does reject it.

The function isdigit() only returns True if ALL of the characters are numbers. I just want to see if the user has entered a number so a sentence like "I own 1 dog" or something.

Any ideas?

kederrac
  • 16,819
  • 6
  • 32
  • 55
DonnellyOverflow
  • 3,981
  • 6
  • 27
  • 39

20 Answers20

477

You can use any function, with the str.isdigit function, like this

def has_numbers(inputString):
    return any(char.isdigit() for char in inputString)

has_numbers("I own 1 dog")
# True
has_numbers("I own no dog")
# False

Alternatively you can use a Regular Expression, like this

import re
def has_numbers(inputString):
    return bool(re.search(r'\d', inputString))

has_numbers("I own 1 dog")
# True
has_numbers("I own no dog")
# False
Sergey Antopolskiy
  • 3,970
  • 2
  • 24
  • 40
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
77

You can use a combination of any and str.isdigit:

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

The function will return True if a digit exists in the string, otherwise False.

Demo:

>>> king = 'I shall have 3 cakes'
>>> num_there(king)
True
>>> servant = 'I do not have any cakes'
>>> num_there(servant)
False
aIKid
  • 26,968
  • 4
  • 39
  • 65
44

Use the Python method str.isalpha(). This function returns True if all characters in the string are alphabetic and there is at least one character; returns False otherwise.

Python Docs: https://docs.python.org/3/library/stdtypes.html#str.isalpha

yadutaf
  • 6,840
  • 1
  • 37
  • 48
K246
  • 1,077
  • 1
  • 8
  • 14
  • 22
    There are other types of characters than alphabetic and numeric - eg, `'_'.isalpha()` is False. – lvc Jun 28 '15 at 02:47
  • 1
    Chars like 'ç' and 'ñ' will not be recognized. The char 'œ' is present in Middle English texts, for instance. – Eduardo Freitas Feb 09 '21 at 14:31
  • The space character is also considered as none alpha using this function, which is a common character in full name for instance. – Ibrahim.H Feb 06 '23 at 22:46
35

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

You should better use regular expression. It's much faster.

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
  • 7,904
  • 5
  • 48
  • 74
12

You could apply the function isdigit() on every character in the String. Or you could use regular expressions.

Also I found How do I find one number in a string in Python? with very suitable ways to return numbers. The solution below is from the answer in that question.

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

Alternatively:

number = filter(str.isdigit, yourString)

For further Information take a look at the regex docu: http://docs.python.org/2/library/re.html

Edit: This Returns the actual numbers, not a boolean value, so the answers above are more correct for your case

The first method will return the first digit and subsequent consecutive digits. Thus 1.56 will be returned as 1. 10,000 will be returned as 10. 0207-100-1000 will be returned as 0207.

The second method does not work.

To extract all digits, dots and commas, and not lose non-consecutive digits, use:

re.sub('[^\d.,]' , '', yourString)
buydadip
  • 8,890
  • 22
  • 79
  • 154
Haini
  • 922
  • 2
  • 12
  • 28
6

I'm surprised that no-one mentionned this combination of any and map:

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

in python 3 it's probably the fastest there (except maybe for regexes) is because it doesn't contain any loop (and aliasing the function avoids looking it up in str).

Don't use that in python 2 as map returns a list, which breaks any short-circuiting

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
6

I'll make the @zyxue answer a bit more explicit:

import re    

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

which is the solution with the fastest benchmark from the solutions that @zyxue proposed on the answer.

Owl
  • 1,446
  • 14
  • 20
Raul
  • 701
  • 7
  • 6
3

You can also use set.intersection It is quite fast, better than regex for small strings.

def contains_number(string):
    return True if set(string).intersection('0123456789') else False
ACe
  • 31
  • 1
2
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)

This code generates a sequence with size n which at least contain an uppercase, lowercase, and a digit. By using the while loop, we have guaranteed this event.

2

Also, you could use regex findall. It's a more general solution since it adds more control over the length of the number. It could be helpful in cases where you require a number with minimal length.

s = '67389kjsdk' 
contains_digit = len(re.findall('\d+', s)) > 0
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
easf
  • 25
  • 5
  • 1
    The problem is clear and does not state it needs control over the length of the number. You are answering another question here. Please upvote or write a comment if you have suggestion for improvements. – BcK Dec 14 '20 at 14:38
2

This too will work.

if any(i.isdigit() for i in s):
    print("True")
laplace
  • 656
  • 7
  • 15
  • Welcome to Stack Overflow! Would you mind explaining what the code does for the people who don't know? Also, a comment about your code. You should make this a function, have a test string, and instead of printing True, returning True and returning False if there are no digits. Thanks! – ᴇɴᴅᴇʀᴍᴀɴ Jun 17 '22 at 19:32
1

What about this one?

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
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
aga
  • 27,954
  • 13
  • 86
  • 121
  • 1
    Please don't just throw your source code here. Be nice and try to give a nice description to your answer, so that others will like it and upvote it. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – sɐunıɔןɐqɐp Jun 15 '18 at 06:19
1

You can use range with count to check how many times a number appears in the string by checking it against the range:

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
sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40
pedmindset
  • 19
  • 3
  • This seems very un-performant. For every character, you're looping 0-10, then linearly scanning the string, going over characters more than once... Just use `isdigit()` – OneCricketeer Mar 24 '21 at 22:47
1

You can use NLTK method for it.

This will find both '1' and 'One' in the text:

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.')
sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40
1

You can accomplish this as follows:

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

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

Using .isdigit() also means not having to resort to exception handling (try/except) in cases where you need to use list comprehension (try/except is not possible inside a list comprehension).

Jaroslav Bezděk
  • 6,967
  • 6
  • 29
  • 46
olisteadman
  • 442
  • 6
  • 12
1

any and ord can be combined to serve the purpose as shown below.

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

A couple of points about this implementation.

  1. any is better because it works like short circuit expression in C Language and will return result as soon as it can be determined i.e. in case of string 'a1bbbbbbc' 'b's and 'c's won't even be compared.

  2. ord is better because it provides more flexibility like check numbers only between '0' and '5' or any other range. For example if you were to write a validator for Hexadecimal representation of numbers you would want string to have alphabets in the range 'A' to 'F' only.

ViFI
  • 971
  • 1
  • 11
  • 27
0

Simpler way to solve is as

s = '1dfss3sw235fsf7s'
count = 0
temp = list(s)
for item in temp:
    if(item.isdigit()):
        count = count + 1
    else:
        pass
print count
BlizZard
  • 587
  • 5
  • 22
  • 3
    Welcome to Stack Overflow! Please don't just throw your source code here. Be nice and try to give a nice description to your answer, so that others will like it and upvote it. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – sɐunıɔןɐqɐp Jun 15 '18 at 06:10
0
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)

This returns all the string that has both alphabets and numbers in it. isalpha() returns the string with all digits or all characters.

Sai ram
  • 9
  • 1
-1

An iterator approach. It consumes all characters unless a digit is met. The second argument of next fix the default value to return when the iterator is "empty". In this case it set to False but also '' works since it is casted to a boolean value in the if.

def has_digit(string):
    str_iter = iter(string)
    while True:
        char = next(str_iter, False)
        # check if iterator is empty
        if char:
            if char.isdigit():
                return True
        else:
            return False

or by looking only at the 1st term of a generator comprehension

def has_digit(string):
    return next((True for char in string if char.isdigit()), False)
cards
  • 3,936
  • 1
  • 7
  • 25
-1

I'm surprised nobody has used the python operator in. Using this would work as follows:

foo = '1dfss3sw235fsf7s'
bar = 'lorem ipsum sit dolor amet'

def contains_number(string):
    for i in range(10):
        if str(i) in list(string):
            return True
    return False

print(contains_number(foo)) #True
print(contains_number(bar)) #False

Or we could use the function isdigit():

foo = '1dfss3sw235fsf7s'
bar = 'lorem ipsum sit dolor amet'

def contains_number(string):
    for i in list(string):
        if i.isdigit():
            return True
    return False

print(contains_number(foo)) #True
print(contains_number(bar)) #False

These functions basically just convert s into a list, and check whether the list contains a digit. If it does, it returns True, if not, it returns False.