تحقق مما إذا كانت السلسلة تحتوي على رقم في 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() ترجع الدالة 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() لن تتصرف الوظيفة كما قد تتوقعها أرقام سلبية أو عائمة. إذا مررنا سلسلة تحتوي على أرقام سالبة أو عائمة فقط، فستعود False، وذلك لأن - و . الأحرف المرتبطة بالأرقام السالبة والعوامات ليست أرقامًا بالفعل.

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

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

على الرغم من ذلك، نظرًا لأن الأحرف هي مجرد سلاسل بطول 1 في بايثون، فيمكنك التكرار من خلال الأحرف واستخدامها 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 في بايثون، فيمكن استخدام هذه الطريقة في حلقة لكل حرف:

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()، وإذا قمت بتمرير سلسلة تحتوي على عدد عشري أو رقم سالب إليها، False يتم إرجاعها نظرًا لأن الأحرف الخاصة ليست أرقامًا. على مستوى الشخصية، على الرغم من ذلك، إذا كان طويلاً True القيمة كافية لتحديد ما إذا كانت السلسلة تحتوي على رقم أم لا، فهي قابلة للتطبيق.

الفرق بين isnumeric() و isdigit()؟

إذن ، ما الفرق بين isnumeric() و isdigit()؟ بينما نحن في ذلك - ماذا عن isdecimal()?

  • isnumeric() يتحقق ما إذا كان أي حرف هو تمثيل يونيكود من قيمة عددية (والتي تشمل التمثيلات الرقمية الرومانية، والأحرف الفوقية، والأحرف السفلية، والكسور)
  • isdigit() يتحقق ما إذا كان أي حرف هو رقم يونيكود (التي لا تتضمن تمثيلات رقمية رومانية، ولكنها تتضمن أرقامًا فائقة/منخفضة وكسورًا)
  • isdecimal() يتحقق مما إذا كانت أي أحرف هي a الرقم العشري (الذي سيعود False لأي شيء ليس كذلك 0..9 في القاعدة 10)

isnumeric() هي الطريقة الأكثر اتساعا، في حين isdecimal() هو الأضيق بين الثلاثة.

تحقق مما إذا كانت السلسلة تحتوي على رقم مع الخريطة () وأي ()

map() تنفذ الوظيفة الوظيفة المقدمة لكل عنصر من عناصر التكرار التي تم تمريرها في وظيفة الخريطة. يتم تمرير كل عنصر من العناصر القابلة للتكرار إلى الدالة كمعلمة:

map(function, iterable)

function يتم تنفيذه لكل عنصر من عناصر iterable. وهذا يسمح بمنطق مرن وقوي للغاية، لا يحده إلا اتساع النطاق function يمكنك الاتصال على المدخلات! ترجع الطريقة أ map المثال، والتي يمكن تحويلها بسهولة إلى مجموعات أخرى مثل القائمة أو المجموعة.

يمكننا كتابة دالة تُرجع قيمة منطقية تمثل ما إذا كان الحرف رقمًا، أم لا map() سيؤدي الاستدعاء بالتالي إلى قائمة القيم المنطقية.

any() عائدات True إذا كان أي عنصر من عناصر التكرار الذي تم تمريره Trueوإلا فإنه يعود False.

من خلال ربط هذين الاثنين معًا، يمكننا إنشاء نص قصير وعالي المستوى وتجريد حلقة for:

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 ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!

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

تحقق مما إذا كانت السلسلة تحتوي على رقم في بايثون مع التعبيرات العادية

التعبيرات العادية هي أنماط البحث مصممة لتكون متطابقة مع نص الإدخال. إنها مرنة ونظرًا لطبيعتها - يمكنك كتابة عدد عشوائي من التعبيرات لنفس النمط للبحث عنه، بالإضافة إلى تغطية أي نمط قابل للتتبع يمكنك التفكير فيه.

بيثون 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() طريقة إرجاع أ re.Match كائن يحتوي على التطابق الذي تم العثور عليه ومؤشرات البداية والنهاية:


يمكن تقييم الكائن إلى قيمة منطقية بناءً على ما إذا كان 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)

بشكل عام، يتم تشغيل أساليب الحلقة في نفس الوقت تقريبًا، مع القليل من الحمل من الأساليب المحددة. لامدا مع any() هي في الواقع الأبطأ (الكثير من العمليات المتكررة، بسبب تحويل قائمة إلى قائمة ثم تقليلها)، في حين أن التعبيرات العادية تتمتع بأسرع وقت تشغيل مع أقل تباين حولها (فهي سريعة باستمرار).

ومع ذلك، في النصوص المدخلة الأطول، يتم التأكيد على التعقيدات الزمنية في كل من الأساليب المختلفة، خاصة اعتمادًا على عدد الأرقام المتطابقة (سواء كانت الأرقام شائعة أم لا):

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)

مع عدد قليل من النتائج – تكون التعبيرات العادية هي الأكثر أداءً. مع العديد من الزيارات، يعد نهج دالة لامدا هو الأكثر أداءً، وهو كذلك يحتفظ بتعقيده الزمني بغض النظر عما إذا كان الإدخال يحتوي على العديد من الزيارات أو واحدة. الجانب السلبي الرئيسي (الحساب الزائد عندما يكون معدل الضرب منخفضًا) يتحول إلى قوته الرئيسية حيث أن التكرار يجعله قويًا للإدخال.

وفي الختام

في هذا البرنامج التعليمي، ألقينا نظرة على طرق متعددة للتحقق مما إذا كانت السلسلة في بايثون تحتوي على حرف واحد على الأقل. لقد ألقينا نظرة على ord(), isnumeric(), isdigit() و isdecimal() الوظيفة، بالإضافة إلى كيفية تجريد هذا المنطق باستخدام استدعاء دالة لامدا باستخدام map() و any(). بعد ذلك، قمنا باستكشاف التعبيرات العادية وقياس الأساليب بمدخلات مختلفة.

الطابع الزمني:

اكثر من ستاكابوز