16

数字と英数字の両方、または数字だけを含むが、アルファだけを含まない文字列を使用しています。誤った一致をテストするには、文字列に少なくとも1桁の数字が含まれているかどうかを確認し、含まれていない場合はエラーメッセージを出力する必要があります。私は次のコードを使用しています:

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またはより簡単な方法はありますか、それともこれで十分ですか?また、文字列にはさまざまな記号('-'、スペースなど)が含まれている可能性があるため、文字列が英数字かどうかを確認することはできません。

4

4 に答える 4

40

これは、正規表現がまさに重要である場所の1つです。

_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

@Wallacollooの回答で説明されているようにanyメソッドを使用できますが、それは単純な正規表現よりも低速です。.isdigit()

>>> 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 OSX10.7のPython2.6でテストされたタイミング。

于 2012-06-27T18:14:47.327 に答える
16

関数を使用anyして、順番に渡します。
シーケンスのいずれかの要素がtrue(つまり、この場合は数字)の場合、anyTrueを返し、それ以外の場合はFalseを返します。https://docs.python.org/library/functions.html#any

def contains_digits(s):
    return any(char.isdigit() for char in s)

ただし、パフォーマンスが心配な場合は、現在の方法の方が実際には高速です。

于 2012-06-27T18:15:46.340 に答える
4

上記の説明を読んだ後、私は次のようなセットベースのバージョンのパフォーマンスに興味がありました。

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)

2台のコンピューターのサンプル実行(各ケースの時間と〜平均):

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
于 2017-10-26T22:33:33.870 に答える
1

より短い解決策を探している人のために:any(d in s for d in'0123456789')

于 2015-12-05T19:14:49.687 に答える