التعبيرات النمطية
أهداف التعلّم
بعد هذا القسم
- ستعرف ما هي التعبيرات النمطية
- ستكون قادرًا على استخدام التعبيرات النمطية في برامجك الخاصة
أثبتنا بالفعل أن بايثون بيئة ممتازة لمعالجة النصوص. ومن الأدوات الإضافية القوية لمعالجة النصوص التعبيرات النمطية (regular expressions)، التي يُختصر اسمها غالبًا بـ regex أو regexp. وهي طريقة لاختيار السلاسل النصية التي تتبع نمطًا معيّنًا والبحث عنها. يقدّم لك هذا القسم أساسيات التعبير النمطي، لكنك ستجد معلومات أكثر بكثير على الإنترنت، بما في ذلك في دليل بايثون.
ما هي التعبيرات النمطية؟
التعبيرات النمطية ليست ميزة خاصة ببايثون فقط. فهي تمثّل، على نحو ما، لغة برمجة داخل لغة برمجة. وهي متوافقة إلى حدٍّ ما عبر العديد من لغات البرمجة المختلفة. وللتعبيرات النمطية صياغتها الخاصة. والفكرة هي تحديد مجموعة من السلاسل النصية التي تتبع قواعد معيّنة.
لنبدأ بمثال بسيط قبل أن نتعمّق أكثر في الصياغة:
import re
words = ["Python", "Pantone", "Pontoon", "Pollute", "Pantheon"]
for word in words:
# the string should begin with "P" and end with "on"
if re.search("^P.*on$", word):
print(word, "found!")
Python found!
Pontoon found!
Pantheon found!
نحتاج إلى import الوحدة re لكي نستخدم التعبيرات النمطية في بايثون. وتحتوي الوحدة re على دوال عديدة للعمل مع التعبيرات النمطية. وفي المثال أعلاه تأخذ الدالة search وسيطين من نوع سلسلة نصية: سلسلة النمط، والسلسلة الهدف التي يُبحث فيها عن النمط.
يبحث هذا المثال الثاني عن أي أعداد في سلسلة نصية. وتعيد الدالة findall قائمة بجميع المواضع التي تطابق النمط:
import re
sentence = "First, 2 !#third 44 five 678xyz962"
numbers = re.findall("\d+", sentence)
for number in numbers:
print(number)
2
44
678
962
صياغة التعبيرات النمطية
لنتعرّف على الصياغة الأساسية للتعبيرات النمطية. وتستخدم معظم الأمثلة التالية برنامج الاختبار هذا:
import re
expression = input("Please type in an expression: ")
while True:
input_string = input("Please type in a string: ")
if input_string == "":
break
if re.search(expression, input_string):
print("Found!")
else:
print("Not found.")
السلاسل الفرعية البديلة
يتيح لك الشريط العمودي |، المسمى أيضًا حرف الأنبوب، مطابقة سلاسل فرعية بديلة. ومعناه إذن أو. على سبيل المثال، يطابق التعبير 911|112 السلاسل النصية التي تتضمن إما السلسلة الفرعية 911 أو السلسلة الفرعية 112.
مثال باستخدام برنامج الاختبار:
Please type in an expression: **aa|ee|ii**
Please type in a string: **aardvark**
Found!
Please type in a string: **feelings**
Found!
Please type in a string: **radii**
Found!
Please type in a string: **smooch**
Not found.
Please type in a string: **continuum**
Not found.
مجموعات الأحرف
تُستخدم الأقواس المربعة للدلالة على مجموعات الأحرف المقبولة. على سبيل المثال، يطابق التعبير [aeio] جميع السلاسل النصية التي تحتوي على أيٍّ من الأحرف a أو e أو i أو o.
يُسمح أيضًا بالشَرطة لمطابقة نطاقات من الأحرف. على سبيل المثال، يطابق التعبير [0-68a-d] جميع السلاسل النصية التي تحتوي على رقم بين 0 و6، أو على الرقم ثمانية، أو على حرف بين a وd. وفي هذه الصياغة تكون جميع النطاقات شاملة للطرفين.
ويتيح لك الجمع بين مجموعتين من الأقواس مطابقة حرفين متتاليين. على سبيل المثال، يطابق التعبير [1-3][0-9] أي عدد مكوّن من رقمين بين 10 و39، شاملًا الطرفين.
مثال باستخدام برنامج الاختبار:
Please type in an expression: **[C-FRSO]**
Please type in a string: **C**
Found!
Please type in a string: **E**
Found!
Please type in a string: **G**
Not found.
Please type in a string: **R**
Found!
Please type in a string: **O**
Found!
Please type in a string: **T**
Not found.
المطابقات المتكرّرة
يمكن تكرار أي جزء من التعبير باستخدام المعاملات التالية:
*يتكرّر لأي عدد من المرات، بما في ذلك الصفر+يتكرّر لأي عدد من المرات، ولكن مرة واحدة على الأقل{m}يتكرّر لعددmمن المرات بالضبط
تعمل هذه المعاملات على الجزء من التعبير الذي يسبق المعامل مباشرةً. على سبيل المثال، يطابق التعبير ba+b السلاسل الفرعية bab وbaab وbaaaaaaaaaaab، من بين غيرها. ويطابق التعبير A[BCDE]*Z السلاسل الفرعية AZ وADZ وABCDEBCDEBCDEZ، من بين غيرها.
مثال باستخدام برنامج الاختبار:
Please type in an expression: **1[234]\*5**
Please type in a string: **15**
Found!
Please type in a string: **125**
Found!
Please type in a string: **145**
Found!
Please type in a string: **12342345**
Found!
Please type in a string: **126**
Not found.
Please type in a string: **165**
Not found.
أحرف خاصة أخرى
النقطة حرف بديل يمكنه مطابقة أي حرف واحد. على سبيل المثال، يطابق التعبير c...o أي سلسلة فرعية من خمسة أحرف تبدأ بـ c وتنتهي بـ o، مثل c-3po أو cello.
يحدّد الحرف ^ أنّ المطابقة يجب أن تكون في بداية السلسلة النصية، ويحدّد $ أنّ المطابقة يجب أن تكون في نهاية السلسلة النصية. ويمكن أيضًا استخدامهما لاستبعاد أي أحرف أخرى غير المحدّدة من المطابقات:
Please type in an expression: **\^[123]\*$**
Please type in a string: **4**
Not found.
Please type in a string: **1221**
Found!
Please type in a string: **333333333**
Found!
تحتاج أحيانًا إلى مطابقة الأحرف الخاصة المحجوزة لصياغة التعبيرات النمطية. ويمكن استخدام الشرطة المائلة العكسية \ لـ تخطّي (escape) الأحرف الخاصة. وهكذا، يطابق التعبير 1+ الرقم 1 مرة أو أكثر، لكن التعبير 1\+ يطابق السلسلة النصية 1+.
Please type in an expression: **^\\\***
Please type in a string: **moi\***
Not found.
Please type in a string: **m\*o\*i**
Not found.
Please type in a string: **\*moi**
Found!
يمكن استخدام الأقواس الدائرية لتجميع أجزاء مختلفة من التعبير معًا. على سبيل المثال، يطابق التعبير (ab)+c السلاسل الفرعية abc وababc وababababababc، لكنه لا يطابق السلسلتين ac أو bc، لأن السلسلة الفرعية ab كاملة يجب أن تظهر مرة واحدة على الأقل.
Please type in an expression: **^(jabba).\*(hut)$**
Please type in a string: **jabba the hut**
Found!
Please type in a string: **jabba a hut**
Found!
Please type in a string: **jarjar the hut**
Not found.
Please type in a string: **jabba the smut**
Not found.
تمرين برمجي: التعبيرات النمطية
إليك بعض التمارين للتعوّد على صياغة التعبيرات النمطية.
أيام الأسبوع
باستخدام تعبير نمطي، اكتب دالة باسم is_dotw(my_string: str). وينبغي أن تعيد الدالة True إذا كانت السلسلة النصية الممرَّرة وسيطًا تحتوي على اختصار لأحد أيام الأسبوع (Mon، Tue، Wed، Thu، Fri، Sat، Sun).
بعض الأمثلة على كيفية عمل الدالة:
print(is_dotw("Mon"))
print(is_dotw("Fri"))
print(is_dotw("Tui"))
True
True
False
التحقق من حروف العلة
اكتب دالة باسم all_vowels(my_string: str) تستخدم تعبيرًا نمطيًا للتحقق مما إذا كانت جميع الأحرف في السلسلة النصية المعطاة حروف علة.
بعض الأمثلة على كيفية عمل الدالة:
print(all_vowels("eioueioieoieou"))
print(all_vowels("autoooo"))
True
False
الوقت من اليوم
اكتب دالة باسم time_of_day(my_string: str) تستخدم تعبيرًا نمطيًا للتحقق مما إذا كانت سلسلة نصية بالصيغة XX:YY:ZZ وقتًا صالحًا في نظام الـ24 ساعة، برقمين لكل من الساعات والدقائق والثواني.
بعض الأمثلة على كيفية عمل الدالة:
print(time_of_day("12:43:01"))
print(time_of_day("AB:01:CD"))
print(time_of_day("17:59:59"))
print(time_of_day("33:66:77"))
True
False
True
False
الختام الكبير
لإنهاء هذا الجزء من المادة، لنعمل أكثر على الكائنات والأصناف من خلال بناء برنامج أكثر توسّعًا قليلًا. لا يتضمن هذا التمرين بالضرورة تعبيرات نمطية، لكن قسمي الدوال كوسائط وإدراكات القوائم سيكونان مفيدين على الأرجح.
وقد تجد أيضًا مجموعة الأمثلة في الجزء 10 مفيدة.
تمرين برمجي: إحصاءات الهوكي
في هذا التمرين ستبني تطبيقًا لفحص إحصاءات دوري الهوكي NHL بضع طرق مختلفة.
يحتوي قالب التمرين على ملفَّي JSON: partial.json وall.json. الملف الأول مخصّص في معظمه للاختبار. أما الثاني فيحتوي على قدر كبير من البيانات، إذ تتضمنه إحصاءات جميع لاعبي NHL لموسم 2019-20.
يكون مدخل اللاعب الواحد بالصيغة التالية:
{
"name": "Patrik Laine",
"nationality": "FIN",
"assists": 35,
"goals": 28,
"penalties": 22,
"team": "WPG",
"games": 68
}
يحتوي الملفان على قائمة من المدخلات بالصيغة أعلاه.
إذا كنت بحاجة إلى تذكير بطريقة التعامل مع ملفات JSON، فانظر إلى الجزء 7 من مادة هذا المقرر.
البحث والقائمة
اكتب تطبيقًا تفاعليًا يسأل أولًا عن اسم الملف، ثم يقدّم الوظائف التالية:
- البحث بالاسم عن إحصاءات لاعب واحد
- سرد جميع اختصارات أسماء الفِرَق بالترتيب الأبجدي
- سرد جميع اختصارات البلدان بالترتيب الأبجدي
تمنحك هذه الوظائف نقطة تمرين واحدة. وينبغي أن يعمل تطبيقك الآن على النحو التالي:
Travis Zajac NJD 9 + 16 = 25
ملاحظة: يجب أن تكون صيغة طباعة اللاعب كما يلي بالضبط:
Leon Draisaitl EDM 43 + 67 = 110
Connor McDavid EDM 34 + 63 = 97
Travis Zajac NJD 9 + 16 = 25
Mike Green EDM 3 + 8 = 11
Markus Granlund EDM 3 + 1 = 4
123456789012345678901234567890123456789
السطر الأخير في المثال أعلاه موجود لمساعدتك على حساب عروض الحقول المختلفة في المخرجات؛ وينبغي ألا تطبع سطر الأرقام هذا بنفسك في الحل النهائي.
يُطبع اختصار الفريق بدءًا من الحرف الثاني والعشرين. وعلامة + هي الحرف الثلاثين، وعلامة = هي الحرف الخامس والثلاثين. وينبغي أن تكون جميع الحقول محاذاة إلى الحافة اليمنى. وجميع المسافات البيضاء هي أحرف مسافة.
من المحتمل أن تكون السلاسل المنسّقة (f-strings) أسهل طريقة لتحقيق المخرجات المطلوبة. وتشبه العملية هذا التمرين من الجزء 6.
سرد اللاعبين حسب النقاط
ستمنحك هاتان الوظيفتان نقطة التمرين الثانية:
- سرد اللاعبين في فريق محدّد بترتيب النقاط المسجَّلة، من الأعلى إلى الأدنى. والنقاط تساوي الأهداف + التمريرات الحاسمة
- سرد اللاعبين من بلد محدّد بترتيب النقاط المسجَّلة، من الأعلى إلى الأدنى
وينبغي أن يعمل تطبيقك الآن على النحو التالي:
Drake Batherson OTT 3 + 7 = 10
Jonathan Davidsson OTT 0 + 1 = 1
اللاعبون الأكثر نجاحًا
ستمنحك هاتان الوظيفتان نقطة التمرين الثالثة:
- قائمة بـ
nمن اللاعبين الذين سجّلوا أكبر عدد من النقاط- إذا تساوى لاعبان في النقاط، يتقدّم من سجّل عددًا أكبر من الأهداف
- قائمة بـ
nمن اللاعبين الذين سجّلوا أكبر عدد من الأهداف- إذا تساوى لاعبان في عدد الأهداف، يتقدّم من لعب عددًا أقل من المباريات
وينبغي أن يعمل تطبيقك الآن على النحو التالي:
Jakub Vrana WSH 25 + 27 = 52
Jared McCann PIT 14 + 21 = 35
يرجى الإجابة عن استبيان سريع حول هذا الجزء من المقرر.
اختبار: (مكون تفاعلي غير متاح في النسخة الثابتة - ID: a03c9f5a-33a9-5aff-8d93-a89625034903)