我正在使用包含数字和字母数字的字符串,或仅包含数字,但不仅仅是alpha。为了测试错误匹配,我需要检查字符串是否包含至少一个数字,如果没有,则打印错误消息。我一直在使用以下代码:
s = '0798237 sh 523-123-asdjlh'
def contains_digits(s):
for char in list(s):
if char.isdigit():
return True
break
return False
if contains_digits(s) == True:
print s
else:
print 'Error'
是否有更多的pythonic或更简单的方法,或者这样做是否足够?另外,我不能只检查字符串是否是字母数字,因为字符串可能包含各种符号(' - ',空格等)
答案 0 :(得分:40)
这是正则表达式就是这样的地方之一:
_digits = re.compile('\d')
def contains_digits(d):
return bool(_digits.search(d))
小演示:
>>> _digits = re.compile('\d')
>>> def contains_digits(d):
... return bool(_digits.search(d))
...
>>> contains_digits('0798237 sh 523-123-asdjlh')
True
>>> contains_digits('sh asdjlh')
False
您可以any
方法使用.isdigit()
方法,如@Wallacolloo's answer中所述,但这比简单正则表达式要慢:
>>> import timeit
>>> timeit.timeit("contains_digits('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits')
0.77181887626647949
>>> timeit.timeit("contains_digits_any('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits_any')
1.7796030044555664
if
方法与正则表达式相同:
>>> timeit.timeit("contains_digits_if('0798237 sh 523-123-asdjlh')", 'from __main__ import contains_digits_if')
0.87261390686035156
但如果数字出现在文本的后面,情况会变得更糟:
>>> timeit.timeit("contains_digits('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits')
1.202538013458252
>>> timeit.timeit("contains_digits_any('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits_any')
5.0348429679870605
>>> timeit.timeit("contains_digits_if('asdjlhtaheoahueoaea 11 thou')", 'from __main__ import contains_digits_if')
3.707183837890625
在Mac OS X 10.7上对python 2.6进行了测试。
答案 1 :(得分:12)
使用any
功能,传递一个序列
如果序列的任何元素为真(即在这种情况下是数字),则any
返回True,否则返回False。 https://docs.python.org/library/functions.html#any
def contains_digits(s):
return any(char.isdigit() for char in s)
如果您担心性能,那么您当前的方法实际上更快。
答案 2 :(得分:1)
对于那些寻求更短解决方案的人:any(d in s for d in'0123456789')
答案 3 :(得分:1)
在阅读上面的讨论之后,我很好奇这样一个基于集合的版本的性能:
def contains_digit(s, digits=set('0123456789')):
return bool(digits.intersection(s))
在我的测试中,平均值比一台计算机上的re
版本略快一些,而另一台计算机上的版本略慢(?)。只是为了好玩,我还比较了其他一些版本。
import math
import re
import timeit
def contains_digit_set_intersection(s, digits=set('0123456789')):
return bool(digits.intersection(s))
def contains_digit_iter_set(s, digits=set('0123456789')):
for c in s:
if c in digits:
return True
return False
def contains_digit_iter_str(s, digits='0123456789'):
for c in s:
if c in digits:
return True
return False
def contains_digit_re(s, digits=re.compile(r'\d')):
return bool(digits.search(s))
def print_times(func, times):
name = func.__name__
average = sum(times) / len(times)
formatted_times = ' '.join('{:.3f}'.format(t) for t in times)
message = '{name:<31} {times} ~{average:.3f}'
print(message.format(name=name, times=formatted_times, average=average))
funcs = [
contains_digit_set_intersection,
contains_digit_iter_set,
contains_digit_iter_str,
contains_digit_re,
]
cases = [
'1bcdefg7',
'abcdefg7',
'abcdefgh',
'0798237 sh 523-123-asdjlh',
'asdjlhtaheoahueoaea 11 thou',
]
for func in funcs:
times = []
for case in cases:
func_case = '{func.__name__}("{case}")'.format(func=func, case=case)
time = timeit.timeit(func_case, globals={func.__name__: func})
times.append(time)
print_times(func, times)
两台计算机的样本运行(每种情况的时间和〜平均值):
contains_digit_set_intersection 0.744 0.731 0.724 1.227 1.113 ~0.908
contains_digit_iter_set 0.264 0.541 0.566 0.260 1.068 ~0.540
contains_digit_iter_str 0.272 0.649 0.632 0.274 1.211 ~0.607
contains_digit_re 0.748 0.854 0.679 0.744 1.006 ~0.806
contains_digit_set_intersection 0.860 0.870 0.855 1.456 1.357 ~1.080
contains_digit_iter_set 0.285 0.613 0.617 0.307 1.163 ~0.597
contains_digit_iter_str 0.295 0.748 0.799 0.288 1.595 ~0.745
contains_digit_re 1.157 1.236 0.927 1.086 1.450 ~1.171