Tjek, om strengen indeholder et tal i Python

Introduktion

Uanset om du bygger et verifikationsscript til brugerinput, er en login-formular, der anmoder brugere om at inkludere et tegn i en adgangskode – at kontrollere, om en streng indeholder et tegn, ikke en ualmindelig operation.

I denne tutorial – vi tager et kig på de mange måder, du kan kontrollere, om en streng indeholder et ciffer/tal i Python, inklusive et benchmark for den mest effektive tilgang i sidste ende.

Tjek, om strengen indeholder tal i Python

Der er flere måder at kontrollere, om en karakter er et tal (ord(), isnumeric(), isdigit()), som du kan koble sammen med en for-loop, for at tjekke for mindst et enkelt positivt hit. Alternativt kan du bruge regulære udtryk som generelle mønstermatchere, som er fleksible, kraftfulde og designet til at blive anvendt på store tekstkorpus. Endelig – det kan du altid map() hver karakter givet en betinget erklæring, og returnere True is any() af dem resulterer i True.

Ved at vælge mellem disse bør der tages hensyn til effektiviteten af ​​metoderne, detaljeringsgraden og kodningsstilen, såvel som opstrøms- eller nedstrømsopgaver forbundet med operationen.

Tjek, om strengen indeholder tal med ord()

ord() funktion tager et tegn og returnerer dets ASCII værdi:

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

ASCII-værdien af 0 er 48, og ASCII-værdien på 9 er 57. Ethvert tal mellem disse vil i forlængelse heraf, har en ASCII-værdi mellem 48 og 57. For nu at kontrollere, om strengen har et tal, vil vi krydse hele inputstrengen og kontrollere ASCII-værdien for hvert tegn, hvis ASCII-værdien er mere end 47 og mindre end 58, betyder det, at det er et tal, og vi vender tilbage 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.")

Dette resulterer i:

Yes, the string contains a number.

Tjek, om strengen indeholder tal med isnumeric()

isnumeric() funktion vender tilbage True hvis inputstrengen kun indeholder tal, ellers returnerer den 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())

Dette resulterer i:

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

Bemærk: isnumeric() funktion vil ikke opføre sig, som du kan forvente negative eller flydende tal. Hvis vi sender en streng med kun negative eller flydende tal, vender den tilbage False, fordi - , . tegn forbundet med negative tal og flydende tal er faktisk ikke tal.

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

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

Men da tegn kun er strenge af længde 1 i Python - kan du iterere gennem karakterer og bruge isnumeric() for at kontrollere, om de er et tal:

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.")

Tjek, om strengen indeholder tal med isdigit()

isdigit() funktion kontrollerer, om alle tegnene i en streng er cifre. Hvis ja - vender den tilbage True, og hvis ikke, vender den tilbage False. Igen, da tegn kun er strenge af længde 1 i Python - denne metode kan bruges i en loop for hvert tegn:

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.")

Bemærk: isdigit() metoden opfører sig kun på samme måde som isnumeric(), og hvis du sender en streng, der indeholder et flydende tal eller et negativt tal, til den, False returneres, fordi specialtegnene ikke er tal. På karakterniveau dog, hvis lige så lang som en True værdi er nok til at bestemme, om strengen indeholder et tal – det er relevant.

Forskellen mellem isnumeric() og isdigit()?

Så hvad er forskellen mellem isnumeric() , isdigit()? Mens vi er i gang – hvad med isdecimal()?

  • isnumeric() kontrollerer, om et tegn er en unicode-repræsentation af en numerisk værdi (som inkluderer romerske numeriske repræsentationer, hævet, nedskrevne og brøker)
  • isdigit() kontrollerer, om et tegn er en unicode ciffer (som ikke inkluderer romerske numeriske repræsentationer, men inkluderer super/sænkede og brøker)
  • isdecimal() kontrollerer, om nogen tegn er en decimal ciffer (som ville vende tilbage False for alt, hvad der ikke er 0..9 i base 10)

isnumeric() er den mest brede metode, mens isdecimal() er den mest snævre mellem de tre.

Tjek, om strengen indeholder tal med map() og enhver()

map() funktionen udfører den angivne funktion for hvert element i den iterable, der sendes i kortfunktionen. Hvert element i en iterabel sendes til funktionen som en parameter:

map(function, iterable)

function udføres for hvert element i iterable. Dette giver mulighed for meget fleksibel og kraftfuld logik, kun begrænset af omfanget af function du kalder på input! Metoden returnerer en map instans, som nemt kan omdannes til andre samlinger, såsom en liste eller et sæt.

Vi kan skrive en funktion, der returnerer en boolean, der repræsenterer, om et tegn er et tal, og map() call vil således resultere i en liste over booleske værdier.

any() afkast True hvis noget element i den beståede iterable er Trueellers vender den tilbage False.

Ved at sætte disse to sammen – kan vi skabe et kort manuskript på højt niveau og abstrahere for-løkken væk:

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)

Dette resulterer i:

Is there a number present? True

Hvis din funktion er en one-liner – er der ingen grund til at udtrække den som en navngivet funktion. Du kan skrive en anonym lambda funktion i stedet for kortheds skyld:

Tjek vores praktiske, praktiske guide til at lære Git, med bedste praksis, brancheaccepterede standarder og inkluderet snydeark. Stop med at google Git-kommandoer og faktisk lærer det!

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)

Dette resulterer også i:

Is there any number present? True

Tjek, om streng indeholder tal i Python med regulære udtryk

Regulære udtryk er søgemønstre designet til at blive matchet med inputtekst. De er fleksible og givet deres natur – du kan skrive et vilkårligt antal udtryk for det samme mønster at søge efter, samt dække ethvert mønster, du kan tænke på.

Pythons re modul bruges til at skrive, kompilere og matche tekst mod regulære udtryk. Det udstiller forskellige metoder, som f.eks match() som matcher om en streng begynder med et mønster, search() som finder den første forekomst af muligvis mange matches i en streng, og findall() som kontrollerer for alle hændelser.

Bemærk: Alle tre metoder accepterer en pattern , search argument og kør en søgning efter pattern i search streng.

Mønsteret, der identificerer en ciffer 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")

search() metode returnerer a re.Match objekt, der indeholder det fundne match og start- og slutindekset:


Objektet kan evalueres til en boolsk værdi baseret på om det er en re.Match objekt eller None. Dette resulterer i:

Is there any number present? Yes

i modsætning til den search() metoden, findall() metode returnerer alle forekomster af mønsteret i stedet for kun den første:

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

Dette resulterer i:

Is there any number present? Yes

Benchmarking

Hvad med præstationen? Hvis du udtrækker logikken og trimmer de unødvendige dele, begrænser metoderne til kun at returnere resultatet, kan du nemt benchmarke dem mod hinanden på det samme input:

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

Dette resulterer i:

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)

Generelt løber for-loop tilgange ind omkring samme tid, med lidt overhead fra de specifikke metoder. Lambda med any() er defacto den langsomste (mange overflødige operationer, på grund af at konvertere en liste til en liste og derefter reducere den), mens Regular Expressions havde den hurtigste kørselstid med den laveste varians omkring sig (de er konsekvent hurtige).

Men på længere inputtekster bliver tidskompleksiteten på hver af de forskellige tilgange understreget, især afhængigt af antallet af matchede cifre (om cifre er almindelige eller ej):

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) 

Den første streng genererer en tilfældig sekvens med omtrent lige mange cifre og tegn, mens sidstnævnte er en streng med kun tegn med et enkelt ciffer til sidst (værste tidskompleksitet):

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

Med et lavt antal hits - Regular Expressions er de mest effektive. Med mange hits er lambdafunktionstilgangen den mest effektive, og den bevarer sin tidskompleksitet uanset om inputtet har mange hits eller et. Den største ulempe (reduntant beregning, når hitraten er lav) bliver til dens vigtigste styrke, da redundans gør den robust til input.

Konklusion

I denne øvelse har vi kigget på flere måder at kontrollere, om en streng i Python indeholder mindst ét ​​tegn. Vi har taget et kig på ord(), isnumeric(), isdigit() , isdecimal() funktion, samt hvordan man abstraherer denne logik med et lambda-funktionskald vha map() , any(). Derefter udforskede vi regulære udtryk og benchmarkede tilgangene med varierende input.

Tidsstempel:

Mere fra Stablemisbrug