Ελέγξτε εάν η συμβολοσειρά περιέχει έναν αριθμό στην Python

Εισαγωγή

Είτε δημιουργείτε ένα σενάριο επαλήθευσης για εισαγωγή χρήστη, είτε μια φόρμα σύνδεσης που ζητά από τους χρήστες να συμπεριλάβουν έναν χαρακτήρα σε έναν κωδικό πρόσβασης – ο έλεγχος εάν μια συμβολοσειρά περιέχει έναν χαρακτήρα δεν είναι μια ασυνήθιστη λειτουργία.

Σε αυτό το σεμινάριο – θα ρίξουμε μια ματιά στους πολλούς τρόπους με τους οποίους μπορείτε να ελέγξετε εάν μια συμβολοσειρά περιέχει ένα ψηφίο/αριθμό στην Python, συμπεριλαμβανομένου ενός σημείου αναφοράς για την πιο αποτελεσματική προσέγγιση στο τέλος.

Ελέγξτε εάν η συμβολοσειρά περιέχει αριθμό στην Python

Υπάρχουν πολλοί τρόποι για να ελέγξετε εάν α χαρακτήρας είναι ένας αριθμός (ord(), isnumeric(), isdigit()), το οποίο μπορείτε να συνδυάσετε με ένα βρόχο for, για να ελέγξετε για τουλάχιστον ένα θετικό χτύπημα. Εναλλακτικά, μπορείτε να χρησιμοποιήσετε κανονικές εκφράσεις ως γενικές αντιστοιχίσεις μοτίβων, οι οποίες είναι ευέλικτες, ισχυρές και σχεδιασμένες να εφαρμόζονται σε μεγάλα σώματα κειμένου. Τέλος - μπορείτε πάντα map() σε κάθε χαρακτήρα δίνεται μια δήλωση υπό όρους και επιστροφή True is any() από αυτά καταλήγουν σε True.

Η επιλογή μεταξύ αυτών θα πρέπει να λαμβάνει υπόψη την αποτελεσματικότητα των μεθόδων, τη λεκτικότητα και το στυλ κωδικοποίησης, καθώς και εργασίες ανάντη ή κατάντη που σχετίζονται με τη λειτουργία.

Ελέγξτε αν η συμβολοσειρά περιέχει αριθμό με ord()

Η ord() η συνάρτηση παίρνει έναν χαρακτήρα και τον επιστρέφει ASCII αξία:

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

Η τιμή ASCII του 0 είναι 48 και η τιμή ASCII του 9 είναι 57. Οποιοσδήποτε αριθμός μεταξύ αυτών, κατ' επέκταση, έχουν τιμή ASCII μεταξύ 48 και 57. Τώρα για να ελέγξουμε αν η συμβολοσειρά έχει κάποιον αριθμό, θα διασχίσουμε ολόκληρη τη συμβολοσειρά εισόδου και θα ελέγξουμε την τιμή ASCII κάθε χαρακτήρα, εάν η τιμή ASCII είναι μεγαλύτερη από 47 και μικρότερη από 58, σημαίνει ότι είναι αριθμός και θα επιστρέψουμε 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.")

Αυτο εχει ως αποτελεσμα:

Yes, the string contains a number.

Ελέγξτε αν η συμβολοσειρά περιέχει αριθμό με isnumeric()

Η isnumeric() επιστρέφει η συνάρτηση True εάν η συμβολοσειρά εισόδου περιέχει μόνο αριθμούς, διαφορετικά, επιστρέφει 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())

Αυτο εχει ως αποτελεσμα:

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

Σημείωση: Η isnumeric() η λειτουργία δεν θα συμπεριφέρεται όπως θα περιμένατε αρνητικούς ή κινητήριους αριθμούς. Αν περάσουμε μια συμβολοσειρά μόνο με αρνητικούς ή float αριθμούς, θα επιστρέψει False, επειδή η - και . Οι χαρακτήρες που σχετίζονται με αρνητικούς αριθμούς και floats είναι πράγματι, όχι αριθμοί.

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

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

Ωστόσο, καθώς οι χαρακτήρες είναι απλώς συμβολοσειρές μήκους 1 στην Python - μπορείτε να επαναλάβετε μέσω χαρακτήρων και να χρησιμοποιήσετε isnumeric() για να ελέγξετε αν είναι αριθμός:

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

Ελέγξτε αν η συμβολοσειρά περιέχει αριθμό με isdigit()

Η isdigit() Η λειτουργία ελέγχει εάν όλοι οι χαρακτήρες μιας συμβολοσειράς είναι ψηφία. Εάν ναι - επιστρέφει True, και αν όχι, επιστρέφει False. Και πάλι, δεδομένου ότι οι χαρακτήρες είναι απλώς συμβολοσειρές μήκους 1 στην Python - αυτή η μέθοδος μπορεί να χρησιμοποιηθεί σε έναν βρόχο για κάθε χαρακτήρα:

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

Σημείωση: Η isdigit() μέθοδος συμπεριφέρεται μόνο με τον ίδιο τρόπο όπως isnumeric(), και αν περάσετε μια συμβολοσειρά που περιέχει ένα float ή έναν αρνητικό αριθμό σε αυτό, False επιστρέφεται επειδή οι ειδικοί χαρακτήρες δεν είναι αριθμοί. Σε επίπεδο χαρακτήρων, όμως, αν είναι τόσο μεγάλο True Η τιμή είναι αρκετή για να προσδιορίσει αν η συμβολοσειρά περιέχει έναν αριθμό - ισχύει.

Διαφορά μεταξύ isnumeric() και isdigit();

Λοιπόν, ποια είναι η διαφορά μεταξύ isnumeric() και isdigit()? Ενώ είμαστε σε αυτό - τι γίνεται με isdecimal()?

  • isnumeric() ελέγχει αν κάποιος χαρακτήρας είναι α αναπαράσταση unicode μιας αριθμητική αξία (που περιλαμβάνει λατινικές αριθμητικές παραστάσεις, εκθέτες, δείκτη και κλάσματα)
  • isdigit() ελέγχει αν κάποιος χαρακτήρας είναι α unicode ψηφίο (το οποίο δεν περιλαμβάνει ρωμαϊκές αριθμητικές αναπαραστάσεις, αλλά περιλαμβάνει υπερ/εγγραφές και κλάσματα)
  • isdecimal() ελέγχει εάν κάποιοι χαρακτήρες είναι α δεκαδικό ψηφίο (που θα επέστρεφε False για οτιδήποτε δεν είναι 0..9 στη βάση 10)

isnumeric() είναι η πιο ευρεία μέθοδος, ενώ isdecimal() είναι το πιο στενό μεταξύ των τριών.

Ελέγξτε αν η συμβολοσειρά περιέχει αριθμό με map() και any()

Η map() Η συνάρτηση εκτελεί την παρεχόμενη συνάρτηση για κάθε στοιχείο του επαναληπτικού που μεταβιβάζεται στη συνάρτηση χάρτη. Κάθε στοιχείο ενός iterable μεταβιβάζεται στη συνάρτηση ως παράμετρος:

map(function, iterable)

Η function εκτελείται για κάθε στοιχείο του iterable. Αυτό επιτρέπει πολύ ευέλικτη και ισχυρή λογική, που περιορίζεται μόνο από την έκταση του function καλείς την είσοδο! Η μέθοδος επιστρέφει a map παράδειγμα, το οποίο μπορεί εύκολα να μετατραπεί σε άλλες συλλογές, όπως λίστα ή σύνολο.

Μπορούμε να γράψουμε μια συνάρτηση που επιστρέφει ένα boolean που αντιπροσωπεύει αν ένας χαρακτήρας είναι αριθμός και το map() Η κλήση θα έχει ως αποτέλεσμα μια λίστα με τιμές boole.

Η any() Επιστροφές True αν κάποιο στοιχείο του περασμένου iterable είναι True, διαφορετικά, επιστρέφει False.

Συνδυάζοντας αυτά τα δύο μαζί – μπορούμε να δημιουργήσουμε ένα σύντομο σενάριο υψηλού επιπέδου και να αφαιρέσουμε το for-loop:

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)

Αυτο εχει ως αποτελεσμα:

Is there a number present? True

Εάν η συνάρτησή σας είναι μία γραμμή - δεν χρειάζεται να την εξαγάγετε ως συνάρτηση με όνομα. Μπορείτε να γράψετε ένα ανώνυμο συνάρτηση λάμδα αντί για λόγους συντομίας:

Ρίξτε μια ματιά στον πρακτικό μας οδηγό για την εκμάθηση του Git, με βέλτιστες πρακτικές, πρότυπα αποδεκτά από τον κλάδο και συμπεριλαμβανόμενο φύλλο εξαπάτησης. Σταματήστε τις εντολές του Git στο Google και πραγματικά μαθαίνουν το!

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)

Αυτό έχει επίσης ως αποτέλεσμα:

Is there any number present? True

Ελέγξτε αν η συμβολοσειρά περιέχει αριθμό στην Python με κανονικές εκφράσεις

Οι κανονικές εκφράσεις είναι μοτίβα αναζήτησης σχεδιασμένο για να ταιριάζει με το κείμενο εισαγωγής. Είναι ευέλικτα και δεδομένης της φύσης τους – μπορείτε να γράψετε έναν αυθαίρετο αριθμό εκφράσεων για το ίδιο μοτίβο προς αναζήτηση, καθώς και να καλύψετε οποιοδήποτε ελκυστικό μοτίβο μπορείτε να σκεφτείτε.

Πύθωνα re Η ενότητα χρησιμοποιείται για τη σύνταξη, τη μεταγλώττιση και την αντιστοίχιση κειμένου με κανονικές εκφράσεις. Εκθέτει διάφορες μεθόδους, όπως π.χ match() που ταιριάζει με το αν μια συμβολοσειρά αρχίζει με ένα μοτίβο, search() που βρίσκει την πρώτη εμφάνιση πιθανώς πολλών αντιστοιχιών σε μια συμβολοσειρά, και findall() που ελέγχει για όλα τα περιστατικά.

Σημείωση: Και οι τρεις μέθοδοι δέχονται α pattern και search όρισμα και εκτελέστε μια αναζήτηση για το pattern στο search σειρά.

Το μοτίβο που προσδιορίζει α ψηφίο 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() η μέθοδος επιστρέφει a re.Match αντικείμενο, που περιέχει την αντιστοιχία που βρέθηκε και τους δείκτες έναρξης και λήξης:


Το αντικείμενο είναι μπορεί να αξιολογηθεί σε μια boolean τιμή με βάση το αν είναι a re.Match αντικείμενο ή None. Αυτο εχει ως αποτελεσμα:

Is there any number present? Yes

Σε αντίθεση με την search() μέθοδο, το findall() Η μέθοδος επιστρέφει όλες τις εμφανίσεις του μοτίβου αντί μόνο της πρώτης:

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

Αυτο εχει ως αποτελεσμα:

Is there any number present? Yes

Βαθμολόγηση επιδόσεων

Τι γίνεται με την απόδοση; Εάν εξαγάγετε τη λογική και περικόψετε τα περιττά μέρη, περιορίζοντας τις μεθόδους μόνο στην επιστροφή του αποτελέσματος, μπορείτε εύκολα να τα μετρήσετε το ένα με το άλλο στην ίδια είσοδο:

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

Αυτο εχει ως αποτελεσμα:

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)

Γενικά, οι προσεγγίσεις for-loop εκτελούνται περίπου την ίδια χρονική στιγμή, με μικρό κόστος από τις συγκεκριμένες μεθόδους. Λάμδα με any() είναι defacto η πιο αργή (πολλές περιττές λειτουργίες, λόγω της μετατροπής μιας λίστας σε λίστα και στη συνέχεια της μείωσής της), ενώ οι Regular Expressions είχαν τον ταχύτερο χρόνο εκτέλεσης με τη χαμηλότερη απόκλιση γύρω από αυτό (είναι σταθερά γρήγορες).

Ωστόσο, σε μεγαλύτερα κείμενα εισαγωγής, οι χρονικές πολυπλοκότητες σε καθεμία από τις διαφορετικές προσεγγίσεις δίνουν έμφαση, ειδικά ανάλογα με τον αριθμό των αντιστοιχισμένων ψηφίων (είτε τα ψηφία είναι κοινά είτε όχι):

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) 

Η πρώτη συμβολοσειρά δημιουργεί μια τυχαία ακολουθία με περίπου ίσο αριθμό ψηφίων και χαρακτήρων, ενώ η τελευταία είναι μια συμβολοσειρά μόνο με χαρακτήρες με ένα μόνο ψηφίο στο τέλος (χειρότερη χρονική πολυπλοκότητα):

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

Με χαμηλό αριθμό επισκέψεων – Οι κανονικές εκφράσεις είναι οι πιο αποδοτικές. Με πολλές επιτυχίες, η προσέγγιση της συνάρτησης λάμδα είναι η πιο αποτελεσματική, και αυτό διατηρεί τη χρονική του πολυπλοκότητα ανεξάρτητα από το αν η είσοδος έχει πολλές επιτυχίες ή μία. Το κύριο μειονέκτημα (περιττός υπολογισμός όταν το ποσοστό επιτυχιών είναι χαμηλό) μετατρέπεται στην κύρια ισχύ του, καθώς ο πλεονασμός το καθιστά ανθεκτικό στην εισαγωγή.

Συμπέρασμα

Σε αυτό το σεμινάριο, ρίξαμε μια ματιά σε πολλούς τρόπους για να ελέγξουμε αν μια συμβολοσειρά στην Python περιέχει τουλάχιστον έναν χαρακτήρα. Ρίξαμε μια ματιά στο ord(), isnumeric(), isdigit() και isdecimal() λειτουργία, καθώς και πώς να αφαιρέσετε αυτή τη λογική με μια κλήση συνάρτησης λάμδα χρησιμοποιώντας map() και any(). Στη συνέχεια, εξερευνήσαμε τις κανονικές εκφράσεις και συγκρίναμε τις προσεγγίσεις με ποικίλα δεδομένα.

Σφραγίδα ώρας:

Περισσότερα από Stackabuse