Controleer of string een nummer bevat in Python

Introductie

Of u nu een verificatiescript bouwt voor gebruikersinvoer, een aanmeldingsformulier dat gebruikers vraagt ​​een teken in een wachtwoord op te nemen - controleren of een tekenreeks een teken bevat, is geen ongewone bewerking.

In deze zelfstudie bekijken we de vele manieren waarop u kunt controleren of een tekenreeks een cijfer/getal bevat in Python, inclusief een maatstaf voor de meest efficiënte benadering uiteindelijk.

Controleer of string een nummer bevat in Python

Er zijn meerdere manieren om te controleren of a karakter is een getal (ord(), isnumeric(), isdigit()), die je kunt koppelen aan een for-lus, om te controleren op ten minste één positieve hit. Als alternatief kunt u reguliere expressies gebruiken als algemene patroonvergelijkers, die flexibel en krachtig zijn en ontworpen om te worden toegepast op grote tekstcorpussen. Eindelijk - dat kan altijd map() elk teken krijgt een voorwaardelijke verklaring en keert terug True is any() daarvan resulteren True.

Bij het kiezen tussen deze moet rekening worden gehouden met de efficiëntie van de methoden, breedsprakigheid en coderingsstijl, evenals stroomopwaartse of stroomafwaartse taken die verband houden met de operatie.

Controleer of string nummer bevat met ord()

De ord() functie neemt een teken en geeft het terug ASCII waarde:

print(ord('0')) 
print(ord('9')) 

De ASCII-waarde van 0 is 48, en de ASCII-waarde van 9 is 57. Elk getal tussen deze, zal bij uitbreiding, hebben een ASCII-waarde tussen 48 en 57. Om nu te controleren of de string een nummer heeft, doorlopen we de hele invoerstring en controleren we de ASCII-waarde van elk teken. Als de ASCII-waarde groter is dan 47 en kleiner dan 58, betekent dit dat het een getal is, en we zullen terugkeren True:

input_string = "My name is Satyam & I am 22 yrs old"
flag = False
for ch in input_string:
    ascii_code = ord(ch)
    if 47 < ascii_code < 58:
        flag = True
        break
if flag:
    print("Yes, the string contains a number.")
else:
    print("No, the string does not contain a number.")

Dit resulteert in:

Yes, the string contains a number.

Controleer of string nummer bevat met isnumeric()

De isnumeric() functie retourneert True als de invoertekenreeks alleen getallen bevat, anders wordt deze geretourneerd False:

str1 = "918"
print("String is whole numeric?", str1.isnumeric())
str2 = "The meaning of the universe is 42"
print("String is whole numeric?", str2.isnumeric())

Dit resulteert in:

String is whole numeric? True 
String is whole numeric? False

Opmerking: De isnumeric() functie zal zich niet gedragen zoals u mag verwachten negatieve of zwevende getallen. Als we een string doorgeven met alleen negatieve of zwevende getallen, zal deze terugkeren FalseOmdat de - en . karakters geassocieerd met negatieve getallen en drijvers zijn inderdaad geen getallen.

str1 = "-918"
print("String is whole numeric?", str1.isnumeric()) 

str2 = "91.8"
print("String is whole numeric?", str2.isnumeric()) 

Hoewel, aangezien karakters in Python slechts strings van lengte 1 zijn, kun je karakters doorlopen en gebruiken isnumeric() om te controleren of ze een nummer zijn:

input_string = "My name is Satyam & I am 22 yrs old"
flag = False
for ch in input_string:
    if ch.isnumeric():
        flag = True
        break
if flag:
    print("Yes, the string contains a number.")
else:
    print("No, the string does not contain a number.")

Controleer of tekenreeks een getal bevat met isdigit()

De isdigit() functie controleert of alle tekens in een string cijfers zijn. Zo ja, dan keert het terug True, en zo niet, dan keert het terug False. Nogmaals, aangezien karakters in Python slechts strings van lengte 1 zijn, kan deze methode voor elk karakter in een lus worden gebruikt:

input_string = "My name is Satyam & I am 22 yrs old"
flag = False
for ch in input_string:
    if ch.isdigit():
        flag = True
        break
if flag:
    print("Yes, the string contains a number.")
else:
    print("No, the string does not contain a number.")

Opmerking: De isdigit() methode gedraagt ​​zich alleen op dezelfde manier als isnumeric(), en als je een string doorgeeft die een float of een negatief getal bevat, False wordt geretourneerd omdat de speciale tekens geen cijfers zijn. Op karakterniveau echter, als het maar één is True waarde is genoeg om te bepalen of de tekenreeks een getal bevat - het is van toepassing.

Verschil tussen isnumeriek() en iscijfer()?

Dus, wat is het verschil tussen isnumeric() en isdigit()? Nu we toch bezig zijn - hoe zit het isdecimal()?

  • isnumeric() controleert of een teken een Unicode-weergave een numerieke waarde (inclusief Romeinse numerieke representaties, superscript, subscript en breuken)
  • isdigit() controleert of een teken een unicode-cijfer (waarin geen Romeinse numerieke representaties zijn opgenomen, maar wel super/subscripts en breuken)
  • isdecimal() controleert of een teken een decimaal cijfer (die zou terugkeren False voor alles wat dat niet is 0..9 in basis 10)

isnumeric() is de meest brede methode, terwijl isdecimal() is de smalste tussen de drie.

Controleer of String Number bevat met map() en any()

De map() functie voert de opgegeven functie uit voor elk element van de iterabele doorgegeven in de kaartfunctie. Elk element van een iterable wordt als een parameter aan de functie doorgegeven:

map(function, iterable)

De function wordt uitgevoerd voor elk item van de iterable. Dit zorgt voor zeer flexibele en krachtige logica, alleen begrensd door de uitgebreidheid van de function jij roept de input op! De methode retourneert a map instantie, die eenvoudig kan worden omgezet in andere verzamelingen, zoals een lijst of set.

We kunnen een functie schrijven die een booleaanse waarde retourneert die aangeeft of een teken een getal is, en de map() call zal dus resulteren in een lijst met booleaanse waarden.

De any() Retourneren True als een element van de doorgegeven iterable is True, anders keert het terug False.

Door deze twee aan elkaar te rijgen, kunnen we een kort script op hoog niveau maken en de for-loop weg abstraheren:

def func(ch):
    return ch.isdigit() 

input_string = "My name is Satyam & I am 22 yrs old"
contains_number = any(list(map(func, input_string)))
print("Is there a number present?", contains_number)

Dit resulteert in:

Is there a number present? True

Als uw functie een oneliner is, hoeft u deze niet uit te pakken als een benoemde functie. U kunt een anoniem schrijven lambda-functie in plaats daarvan kortheidshalve:

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

input_string = "My name is Satyam & I am 22 yrs old"
contains_number = any(list(map(lambda ch: ch.isdigit(), input_string)))
print("Is there any number present?", contains_number)

Dit resulteert ook in:

Is there any number present? True

Controleer of String Number bevat in Python met reguliere expressies

Reguliere expressies zijn zoek patronen ontworpen om te worden vergeleken met invoertekst. Ze zijn flexibel en gezien hun aard - u kunt een willekeurig aantal uitdrukkingen schrijven voor hetzelfde patroon om naar te zoeken, en u kunt elk denkbaar patroon behandelen.

Python's re module wordt gebruikt om tekst te schrijven, compileren en matchen met reguliere expressies. Het legt verschillende methoden bloot, zoals match() die overeenkomt met of een string begint met een patroon, search() waarmee het eerste voorkomen van mogelijk veel overeenkomsten in een tekenreeks wordt gevonden, en findall() die controleert op alle gebeurtenissen.

Opmerking: Alle drie de methoden accepteren a pattern en search argument en voer een zoekopdracht uit naar de pattern in de search string.

Het patroon dat a identificeert cijfer is "d+":

import re
input_string = "My name is Satyam & I am 22 yrs old"
match = re.search(r"d+", input_string)
if match:
    print("Is there any number present?", "Yes")
else:
    print("Is there any number present?", "No")

De search() methode retourneert een re.Match object, met daarin de gevonden overeenkomst en de begin- en eindindexen:


Het object kan worden geëvalueerd tot een booleaanse waarde op basis van het feit of het een re.Match object of None. Dit resulteert in:

Is there any number present? Yes

In tegenstelling tot het search() methode, de findall() methode retourneert alle exemplaren van het patroon in plaats van alleen de eerste:

import re
input_string = "My name is Satyam & I am 22 yrs old"
match = re.findall(r"d+", input_string)
if match:
    print("Is there any number present?", "Yes")
else:
    print("Is there any number present?", "No")

Dit resulteert in:

Is there any number present? Yes

Benchmarking

Hoe zit het met de prestaties? Als u de logica extraheert en de onnodige delen bijsnijdt, waarbij u de methoden beperkt tot het retourneren van alleen het resultaat, kunt u ze eenvoudig met elkaar vergelijken op dezelfde invoer:

%timeit ord_check()
%timeit isnumeric_check()
%timeit is_digit_check()
%timeit lambda_check()
%timeit regex_check()

Dit resulteert in:

2.18 µs ± 51.5 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
2.04 µs ± 639 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
1.88 µs ± 448 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
5.07 µs ± 915 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
1.47 µs ± 3.41 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

Over het algemeen lopen de for-loop-benaderingen rond dezelfde tijd, met weinig overhead van de specifieke methoden. Lambda met any() is de facto de langzaamste (veel overbodige bewerkingen, vanwege het converteren van een lijst naar een lijst en deze vervolgens verkleinen), terwijl reguliere expressies de snelste runtime hadden met de laagste variantie eromheen (ze zijn consistent snel).

Bij langere invoerteksten wordt de tijdcomplexiteit van elk van de verschillende benaderingen echter benadrukt, vooral afhankelijk van het aantal overeenkomende cijfers (of cijfers gebruikelijk zijn of niet):

import random
import string

input_string_random = ''.join(random.choices(string.ascii_uppercase + string.digits, k=1000))
print(input_string_random) 

input_string_with_single_digit = ''.join(random.choices(string.ascii_uppercase, k=1000)) + '1'
print(input_string_with_single_digit) 

De eerste string genereert een willekeurige reeks met ongeveer een gelijk aantal cijfers en tekens, terwijl de laatste een tekenreeks is met uiteindelijk een enkel cijfer (slechtste tijdscomplexiteit):

%timeit ord_check(input_string_random)
504 ns ± 22.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit ord_check(input_string_with_single_digit)
76.2 µs ± 1.36 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit isnumeric_check(input_string_random)
756 ns ± 170 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit isnumeric_check(input_string_with_single_digit)
76.2 µs ± 8.43 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit is_digit_check(input_string_random)
549 ns ± 102 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit is_digit_check(input_string_with_single_digit)
65 µs ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit lambda_check(input_string_random)
114 µs ± 8.77 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit lambda_check(input_string_with_single_digit)
119 µs ± 6.23 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
%timeit regex_check(input_string_random)
996 ns ± 19.8 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
%timeit regex_check(input_string_with_single_digit)
22.2 µs ± 1.77 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

Met een laag aantal hits zijn reguliere expressies het meest performant. Met veel hits is de lambda-functiebenadering de meest performante, en dat is het ook behoudt zijn tijdcomplexiteit ongeacht of de invoer veel treffers heeft of één. Het belangrijkste nadeel (overtollige berekeningen wanneer het slagingspercentage laag is) wordt omgezet in zijn belangrijkste kracht, aangezien redundantie het robuust maakt om in te voeren.

Conclusie

In deze zelfstudie hebben we meerdere manieren bekeken om te controleren of een tekenreeks in Python ten minste één teken bevat. We hebben gekeken naar de ord(), isnumeric(), isdigit() en isdecimal() functie, evenals hoe deze logica te abstraheren met een lambda-functieaanroep met behulp van map() en any(). Vervolgens hebben we reguliere expressies verkend en de benaderingen gebenchmarkt met verschillende input.

Tijdstempel:

Meer van Stapelmisbruik