value = 'ad.41.bd'
if len(value) == len(value.strip({0,1,2,3,4,5,6,7,8,9})):
# no numbers
else:
# numbers present
There a cleaner way of detecting numbers in a string in Python?
>>> value="ab3asdf"
>>> any(c.isdigit() for c in value)
True
>>> value="asf"
>>> any(c.isdigit() for c in value)
False
>>> value = 'ad.41.bd'
>>> any(map(lambda c:c.isdigit(),value))
True
EDIT:
>>> value="1"+"a"*10**6
>>> any(map(lambda c:c.isdigit(),value))
True
>>> from itertools import imap
>>> any(imap(lambda c:c.isdigit(),value))
True
map took 1 second (on old python) imap was instant because imap returns a generator. note often in the real world there is a higher probability of the number being at the end of the file name.
any, but map generates the entire list first. If value is huge and the first character is a digit, this code still processes the whole thing.True! Try it with value = 'abc'.any(c.isdigit() for c in value) uses a generator expression and dispenses with the lambda and the map.from string import digits
def containsnumbers(value):
return any(char in digits for char in value)
And just for thoroughness:
any(c.isdigit()):
>>> timeit.timeit('any(c.isdigit() for c in value)', setup='value = "abcd1"')
1.4080650806427002
any(c in digits):
>>> timeit.timeit('any(c in digits for c in value)', setup='from string import digits; value = "abcd1"')
1.392179012298584
re.search (1 or more digits):
>>> timeit.timeit("re.search('\d+', value)", setup='import re; value = "abcd1"')
1.8129329681396484
re.search (stop after one digit):
>>> timeit.timeit("re.search('\d', value)", setup='import re; value = "abcd1"')
1.599431037902832
re.match (non-greedy):
>>> timeit.timeit("re.match(r'^.*?\d', value)", setup='import re; value = "abcd1"')
1.6654980182647705
re.match(greedy):
>>> timeit.timeit("re.match(r'^.*\d', value)", setup='import re; value = "abcd1"')
1.5637178421020508
any(map()):
>>> timeit.timeit("any(map(lambda c:c.isdigit(),value))", setup='value = "abcd1"')
1.9165890216827393
any(imap()):
>>> timeit.timeit("any(imap(lambda c:c.isdigit(),value))", setup='from itertools import imap;value = "abcd1"')
1.370448112487793
Generally, the less complex regexps ran more quickly. c.isdigit() and c in digits are almost equivalent. re.match is slightly faster than re.search. map() is the slowest solution, but imap() was the fastest (but within rounding error of any(c.isdigit) and any(c in digits).
value to "abcd" * 1000 + "9" and decreased number to 10000. any(imap) took 7.588s, re.search (stop after first match) took 0.377s, and any(c in digits) took 4.283s. Rewriting the last as any(d in value for d in digits) took only .310s (and .073s when the last digit was "1" instead of "9"), again I suppose because it pushed most of the workload to off to core.You can use a regular expression:
import re
# or if re.search(r'\d', value):
if re.match(r'^.*?\d', value):
# numbers present
else:
# no numbers
^ and would probably be better off with re.search. Also, .* matches zero or more characters so ? is redundant.search might look for all locations that match this pattern (by I need only one), whereas match will only match at the beginning (so yes, I could omit ^ here). I want the shortest possible match, hence the .*? (not greedy).search give only the first match.