Sprawdź, czy ciąg zawiera liczbę

194

Większość pytań, które znalazłem, jest stronnicza w tym, że szukają liter w swoich liczbach, podczas gdy szukam liczb w ciągach, w których chciałbym być ciągiem niezliczonych liczb. Muszę wpisać ciąg i sprawdzić, czy zawiera on jakieś liczby i czy go odrzuca.

Funkcja isdigit()zwraca tylko Truewtedy, gdy WSZYSTKIE znaki są cyframi. Chcę tylko sprawdzić, czy użytkownik wprowadził numer, a więc zdanie takie jak "I own 1 dog"czy coś takiego.

Jakieś pomysły?

DonnellyOverflow
źródło

Odpowiedzi:

293

Możesz użyć anyfunkcji z str.isdigitfunkcją w ten sposób

>>> def hasNumbers(inputString):
...     return any(char.isdigit() for char in inputString)
... 
>>> hasNumbers("I own 1 dog")
True
>>> hasNumbers("I own no dog")
False

Alternatywnie możesz użyć wyrażenia regularnego, takiego jak to

>>> 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
źródło
Co z liczbami ujemnymi?
Ray
@Ray Następnie RegEx można przedłużyć w ten sposóbr'-?\d+'
theourourheheye
15
Czy oryginalne wyrażenie regularne i tak nie wykrywa liczb ujemnych?
zmieszany 00
1
@ confused00 Nie, \ddopasuje tylko jedną cyfrę w zakresie 0do 9.
theourourhehe
9
@tourfhetye: -1 wciąż jest cyfrą. Jest to myślnik, po którym następuje cyfra „1”
użytkownik3183018
50

Możesz użyć kombinacji anyi str.isdigit:

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

Funkcja zwróci, Truejeśli w ciągu istnieje cyfra. W przeciwnym razieFalse . W .

Próbny:

>>> king = 'I shall have 3 cakes'
>>> num_there(king)
True
>>> servant = 'I do not have any cakes'
>>> num_there(servant)
False
aIKid
źródło
Nie trzeba tworzyć tymczasowej listy, zamiast tego można użyć wyrażenia generatora, usuwając tylko nawiasy kwadratowe.
Matteo Italia,
Ach tak, właśnie zrozumiałem, że anyakceptuje wyrażenia generatora.
aIKid
30

posługiwać się

str.isalpha () 

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

Zwraca wartość true, jeśli wszystkie znaki w ciągu są alfabetyczne i istnieje co najmniej jeden znak, w przeciwnym razie false.

K246
źródło
8
Istnieją inne typy znaków niż alfabetyczne i numeryczne - np '_'.isalpha(). „False”.
lvc
28

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

Lepiej użyj wyrażenia regularnego. Jest znacznie szybszy.

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
źródło
f3 nic nie zwraca
pyd
Oznacza to, że nie ma dopasowania, zwracaNone
zyxue
RE_D = re.compile ('\ d') def has_digits (string): res = RE_D.search (string) return res is not None
Raul
8

Możesz zastosować funkcję isdigit () do każdego znaku w ciągu. Lub możesz użyć wyrażeń regularnych.

Znalazłem również Jak znaleźć jedną liczbę w ciągu znaków w Pythonie? z bardzo odpowiednimi sposobami zwracania liczb. Poniższe rozwiązanie pochodzi z odpowiedzi na to pytanie.

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

Alternatywnie:

number = filter(str.isdigit, yourString)

Aby uzyskać więcej informacji, zobacz dokumentację regularną: http://docs.python.org/2/library/re.html

Edycja: Zwraca rzeczywiste liczby, a nie wartość logiczną, więc powyższe odpowiedzi są bardziej poprawne w twoim przypadku

Pierwsza metoda zwróci pierwszą cyfrę i kolejne kolejne cyfry. Zatem 1,56 zostanie zwrócone jako 1. 10 000 zostanie zwrócone jako 10. 0207-100-1000 zostanie zwrócone jako 0207.

Druga metoda nie działa.

Aby wyodrębnić wszystkie cyfry, kropki i przecinki i nie zgubić kolejnych cyfr, użyj:

re.sub('[^\d.,]' , '', yourString)
Haini
źródło
3

Możesz do tego użyć metody NLTK.

W tekście znajdzie się zarówno „1”, jak i „jeden”:

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
źródło
2

Możesz to zrobić w następujący sposób:

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

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

Używanie .isdigit()oznacza także brak konieczności uciekania się do obsługi wyjątków (try / wyjątek) w przypadkach, w których musisz użyć rozumienia listy (próba / wyjątek nie jest możliwa w ramach rozumienia listy).

olisteadman
źródło
2

Możesz użyć zakresu z liczbą, aby sprawdzić, ile razy liczba pojawia się w ciągu, sprawdzając ją względem zakresu:

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
zestaw pedałów
źródło
2

Dziwi mnie, że nikt nie wspomniał o tej kombinacji anyi map:

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

w Pythonie 3 prawdopodobnie jest tam najszybszy (z wyjątkiem być może wyrażeń regularnych), ponieważ nie zawiera żadnej pętli (a aliasing funkcji unika wyszukiwania str).

Nie używaj tego w Pythonie 2, ponieważ mapzwraca a list, które przerywa anyzwarcie

Jean-François Fabre
źródło
2

A co z tym?

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
źródło
1
Proszę nie rzucać tutaj tylko kodu źródłowego. Bądź miły i postaraj się podać ładny opis swojej odpowiedzi, aby inni polubili ją i głosowali za nią. Zobacz: Jak napisać dobrą odpowiedź?
sɐunıɔ ןɐ qɐp
2

Sprawię, że odpowiedź @zyxue będzie bardziej wyraźna:

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

które jest rozwiązaniem z najszybszym testem porównawczym spośród rozwiązań zaproponowanych przez @zyxue w odpowiedzi.

Raul
źródło
1

Prostszym sposobem rozwiązania jest jak

s = '1dfss3sw235fsf7s'
count = 0
temp = list(s)
for item in temp:
    if(item.isdigit()):
        count = count + 1
    else:
        pass
print count
Burza śnieżna
źródło
1
Witamy w Stack Overflow! Proszę nie rzucać tutaj tylko kodu źródłowego. Bądź miły i postaraj się podać ładny opis swojej odpowiedzi, aby inni polubili ją i głosowali za nią. Zobacz: Jak napisać dobrą odpowiedź?
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)

Ten kod generuje sekwencję o rozmiarze n, która przynajmniej zawiera wielkie litery, małe litery i cyfrę. Korzystając z pętli while, gwarantujemy to zdarzenie.

Mehran Attar
źródło
Dodaj wyjaśnienie do swojej odpowiedzi
Mastisa,
1

anyi ordmożna je łączyć, aby osiągnąć cel, jak pokazano poniżej.

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

Kilka uwag na temat tej implementacji.

  1. any jest lepszy, ponieważ działa jak wyrażenie zwarcia w języku C i zwróci wynik, gdy tylko będzie można go określić, tj. w przypadku łańcucha „a1bbbbbbc” b i „c” nawet nie zostaną porównane.

  2. ordjest lepszy, ponieważ zapewnia większą elastyczność, np. numery kontrolne tylko między „0” a „5” lub dowolnym innym zakresem. Na przykład, jeśli chcesz napisać walidator dla szesnastkowej reprezentacji liczb, chciałbyś, aby ciąg zawierał alfabety tylko w zakresie od „A” do „F”.

ViFI
źródło
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)

Zwraca cały ciąg zawierający zarówno alfabety, jak i liczby. isalpha () zwraca ciąg zawierający wszystkie cyfry lub wszystkie znaki.

Sai ram
źródło
0

To prawdopodobnie nie jest najlepsze podejście w Pythonie, ale jako Haskeller to podejście lambda / mapa miało dla mnie idealny sens i jest bardzo krótkie:

anydigit = lambda x: any(map(str.isdigit, x))

Oczywiście nie trzeba go nazywać. Nazwany może być używany jak anydigit("abc123"), co wydaje mi się tym, czego szukałem!

Oscar South
źródło