الاثنين، 28 أكتوبر 2024

كيفية مطابقة كلمة محددة في تعبيرات بايثون العادية؟ (الإجابة: لا تفعل ذلك)

 يكشف السؤال عن احتمال وجود بعض الفجوات في فهم أساسيات مكتبة التعبيرات العادية في Python.

إذا كنت شخصًا غير صبور، فإليك الإجابة المختصرة:


لمطابقة سلسلة دقيقة “hello” جزئيًا في “hello world”، استخدم التعبير العادي البسيط “hello”. ومع ذلك، فإن النهج الأكثر بساطة والأكثر استخدامًا لـ Python هو استخدام الكلمة الأساسية in ضمن تعبير العضوية “hello” في “hello world”.

للحصول على تطابق كامل، استخدم رموز البداية والنهاية ‘^hello$‘ التي لن تتطابق مع السلسلة ‘hello world’ ولكنها ستتطابق مع ‘hello’.

حتى الآن كان كل شيء على ما يرام. ولكن دعنا نتطرق إلى بعض الأسئلة الأكثر تحديدًا، لأنك ربما لم تكن تبحث عن هذه الإجابة البسيطة.

في الواقع، هناك طرق متعددة لفهم سؤالك وقد حاولت العثور على جميع التفسيرات والإجابة عليها واحدة تلو الأخرى في هذا البرنامج التعليمي:

  • كيفية التحقق من عضوية كلمة في سلسلة بدون استخدام مكتبة؟
  • كيفية مطابقة سلسلة دقيقة باستخدام مكتبة regex في Python؟
  • كيفية مطابقة كلمة في سلسلة باستخدام حدود الكلمات \b؟
  • كيفية مطابقة كلمة في سلسلة (غير حساسة لحالة الأحرف)؟
  • كيفية العثور على جميع تكرارات الكلمة في سلسلة؟
  • كيفية العثور على جميع الأسطر التي تحتوي على كلمة محددة؟

دعنا نتعمق في كل واحدة منها لمعرفة وتحسين التعبيرات العادية!

كيفية التحقق من عضوية كلمة في سلسلة (Python Built-In)؟

لمطابقة سلسلة دقيقة “hello” في سلسلة مثل “hello world”، استخدم الكلمة الأساسية in ضمن تعبير العضوية 'hello' in 'hello world'“.

هذه هي الإجابة البسيطة، لقد تعلمتها بالفعل.

بدلاً من مطابقة سلسلة دقيقة، غالبًا ما يكون من الكافي استخدام كلمة in الأساسية في Python للتحقق من العضوية. نظرًا لأن هذه وظيفة مدمجة فعالة للغاية في Python، فهي أسرع كثيرًا، وأكثر قابلية للقراءة، ولا تتطلب تبعيات خارجية.

لذلك، يجب عليك الاعتماد على هذه الطريقة إذا كان ذلك ممكنا:

1
2
>>> 'hello' in 'hello world'
True

يوضح المثال الأول الطريقة الأكثر مباشرة للقيام بذلك: ببساطة اسأل بايثون عما إذا كانت السلسلة “داخل” سلسلة أخرى. يُطلق على هذا عامل العضوية وهو فعال للغاية.

يمكنك أيضًا التحقق من عدم ظهور سلسلة في سلسلة أخرى.

1
2
>>> 'hi' not in 'hello world'
True

يعيد عامل العضوية السالب s1 not in s2 القيمة True إذا لم تظهر السلسلة s1 في السلسلة s2.

ولكن هناك مشكلة في عامل العضوية. قيمة الإرجاع هي قيمة منطقية.

ومع ذلك، فإن ميزة مكتبة التعبيرات العادية re في Python هي أنها تقوم بإرجاع كائن مطابقة يحتوي على معلومات أكثر إثارة للاهتمام مثل الموقع الدقيق للسلسلة الفرعية المطابقة.

دعونا نستكشف مشكلة مطابقة السلسلة الدقيقة باستخدام مكتبة regex بعد ذلك:

كيفية مطابقة سلسلة دقيقة (Regex)؟

لمطابقة سلسلة دقيقة باستخدام مكتبة التعبيرات العادية re في Python، استخدم السلسلة كتعبير عادي. على سبيل المثال، يمكنك استدعاء re.search('hello', 'hello world') لمطابقة السلسلة الدقيقة ‘hello’ في السلسلة ‘hello world’ وإرجاع كائن المطابقة

إليك كيفية مطابقة سلسلة فرعية دقيقة في سلسلة معينة:

1
2
3
>>> import re
>>> re.search('hello', 'hello world')
<re.Match object; span=(0, 5), match='hello'>

بعد استيراد مكتبة Python لمعالجة التعبيرات العادية re، يمكنك استخدام طريقة re.search(pattern, string) للعثور على أول ظهور للنمط في السلسلة.

يؤدي هذا إلى إرجاع كائن مطابقة يلف الكثير من المعلومات المفيدة مثل مواضع المطابقة عند البداية والنهاية والسلسلة الفرعية المطابقة.

أثناء البحث عن تطابقات دقيقة للسلسلة، ستكون السلسلة الفرعية المطابقة دائمًا هي نفسها الكلمة التي تبحث عنها.

لكن انتظر، هناك مشكلة أخرى: كنت تريد تطابقًا دقيقًا، أليس كذلك؟

إن استخدام الطريقة السابقة لا يساعدك لأنك تحصل على تطابقات البادئة للكلمة التي بحثت عنها:

1
2
>>> re.search('good', 'goodbye')
<re.Match object; span=(0, 4), match='good'>

عند البحث عن الكلمة الدقيقة ‘good’ في السلسلة ‘goodbye’، فإنها تتطابق فعليًا مع بادئة الكلمة.

هل هذا ما أردته؟ إذا لم يكن كذلك، اقرأ:

كيفية مطابقة كلمة في سلسلة (حدود الكلمة \b)؟

سيؤدي التطابق الدقيق للكلمة أيضًا إلى استرجاع السلاسل الفرعية المطابقة التي تظهر في أي مكان في السلسلة.

وهنا مثال:

1
2
>>> 'no' in 'nobody knows'
True

مثال آخر:

1
2
>>> re.search('see', 'dfjkyldsssseels')
<re.Match object; span=(10, 13), match='see'>

ماذا لو كنت تريد مطابقة الكلمات بأكملها فقط وليس السلاسل الفرعية الدقيقة؟

الجواب بسيط:

لمطابقة الكلمات بالكامل بدقة، استخدم حرف حد الكلمة ‘\b‘. يتطابق هذا الحرف في بداية ونهاية كل كلمة، لكنه لا يستهلك أي شيء. بعبارة أخرى، يتحقق ببساطة مما إذا كانت الكلمة تبدأ أو تنتهي في هذا الموضع (عن طريق التحقق من المسافات البيضاء أو الأحرف غير المرتبطة بالكلمات).

فيما يلي كيفية استخدام حرف حدود الكلمة للتأكد من تطابق الكلمات الكاملة فقط:

1
2
3
4
5
>>> import re
>>> re.search(r'\bno\b', 'nobody knows')
>>>
>>> re.search(r'\bno\b', 'nobody knows nothing - no?')
<re.Match object; span=(23, 25), match='no'>

في كلا المثالين، يمكنك استخدام نفس التعبير العادي '\bno\b' الذي يبحث عن الكلمة الدقيقة 'no' ولكن فقط إذا كان حرف حدود الكلمة '\b' يتطابق قبل وبعد.

بمعنى آخر، يجب أن تظهر كلمة ‘no’ بمفردها ككلمة منفصلة. ولا يجوز ظهورها ضمن تسلسل آخر من أحرف الكلمة.

نتيجة لذلك، لا يتطابق التعبير العادي في السلسلة “‘nobody knows'”، لكنه يتطابق في السلسلة “‘nobody knows nothing – no?'”.

لاحظ أننا نستخدم السلسلة الخام r'...'لكتابة التعبيرات العادية حتى يعمل تسلسل الإفلات '\b' في السلسلة.

  • بدون السلسلة الخام، سوف يفترض بايثون أنها عبارة عن حرف مائل عكسي غير مهرب '\'، متبوعًا بالحرف 'b'.
  • مع السلسلة الخام، ستكون كل الخطوط المائلة العكسية كما يلي: خطوط مائلة عكسية. ثم يفسر محرك التعابير العادية الحرفين كحرف ميتا خاص واحد: حدود الكلمة '\b'.

ولكن ماذا لو لم تكن مهتمًا إذا كانت الكلمة مكتوبة بأحرف كبيرة أو صغيرة أو كبيرة؟ بعبارة أخرى:

كيفية مطابقة كلمة في سلسلة (غير حساسة لحالة الأحرف)؟

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

وإليك الطريقة:

1
2
3
4
5
6
7
>>> import re
>>> re.search('no', 'NONONON', flags=re.IGNORECASE)
<re.Match object; span=(0, 2), match='NO'>
>>> re.search('no', 'NONONON', flags=re.I)
<re.Match object; span=(0, 2), match='NO'>
>>> re.search('(?i)no', 'NONONON')
<re.Match object; span=(0, 2), match='NO'>

كل الطرق الثلاث متكافئة: حيث تتجاهل جميعها استخدام الأحرف الكبيرة في الكلمة.

يستخدم المثال الثالث علامة (?i) والتي تعني أيضًا: “تجاهل الأحرف الكبيرة”.

كيفية العثور على جميع تكرارات الكلمة في سلسلة؟

حسنًا، أنت لا تشعر بالرضا أبدًا، أليس كذلك؟ لذا دعنا نستكشف كيفية العثور على جميع تكرارات كلمة في سلسلة.

في الأمثلة السابقة، استخدمت طريقة re.search(pattern, string) للعثور على أول تطابق للنمط في السلسلة.

بعد ذلك، ستتعلم كيفية العثور على جميع التكرارات (ليس فقط المطابقة الأولى) باستخدام طريقة re.findall(pattern, string).

1
2
3
>>> import re
>>> re.findall('no', 'nononono')
['no', 'no', 'no', 'no']

يسترجع الكود الخاص بك جميع السلاسل الفرعية المطابقة.

إذا كنت بحاجة إلى العثور على كافة الكائنات المطابقة بدلاً من السلاسل الفرعية المطابقة، فيمكنك استخدام طريقة re.finditer(pattern, string):

1
2
3
4
5
6
7
8
9
10
>>> for match in re.finditer('no', 'nonononono'):
    print(match)
 
     
<re.Match object; span=(0, 2), match='no'>
<re.Match object; span=(2, 4), match='no'>
<re.Match object; span=(4, 6), match='no'>
<re.Match object; span=(6, 8), match='no'>
<re.Match object; span=(8, 10), match='no'>
>>>

تنشئ طريقة re.finditer(pattern, string) مُكررًا يتكرر على جميع المطابقات ويعيد كائنات المطابقة. بهذه الطريقة، يمكنك العثور على جميع المطابقات والحصول على كائنات المطابقة أيضًا.

كيفية العثور على جميع الأسطر التي تحتوي على كلمة دقيقة؟

لنفترض أنك تريد العثور على جميع الأسطر التي تحتوي على الكلمة “42” من سلسلة نصية متعددة الأسطر في Python.

تستخدم الإجابة تخصصًا جيدًا في تعبيرات Python العادية: حيث يتطابق تعبير النقطة العادية مع جميع الأحرف، باستثناء حرف السطر الجديد. وبالتالي، فإن تعبير النقطة العادية '.*' سيتطابق مع جميع الأحرف في سطر معين (ولكنه يتوقف بعد ذلك).

إليك كيفية استخدام هذه الحقيقة للحصول على جميع الأسطر التي تحتوي على كلمة معينة:

1
2
3
4
5
6
7
>>> import re
>>> s = '''the answer is 42
the answer: 42
42 is the answer
43 is not'''
>>> re.findall('.*42.*', s)
['the answer is 42', 'the answer: 42', '42 is the answer']

تحتوي ثلاثة أسطر من أصل أربعة أسطر على الكلمة “42”. تقوم طريقة findall() بإرجاع هذه الأسطر على هيئة سلاسل.

كيفية العثور على جميع الأسطر التي لا تحتوي على كلمة دقيقة؟

في القسم السابق، تعلمت كيفية العثور على جميع الأسطر التي تحتوي على كلمة محددة.

في هذا القسم، ستتعلم كيفية القيام بالعكس: العثور على جميع الأسطر التي لا تحتوي على كلمة دقيقة.

هذا الأمر أكثر تعقيدًا بعض الشيء. سأعرض لك الكود أولاً ثم أشرحه بعد ذلك:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import re
s = '''the answer is 42
the answer: 42
42 is the answer
43 is not
the answer
42'''
 
for match in re.finditer('^((?!42).)*$', s, flags=re.M):
    print(match)
 
     
'''
<re.Match object; span=(49, 58), match='43 is not'>
<re.Match object; span=(59, 69), match='the answer'>
'''

يمكنك أن ترى أن الكود يتطابق بنجاح فقط مع الأسطر التي لا تحتوي على السلسلة ’42’.

كيف يمكنك فعل ذلك؟

الفكرة العامة هي مطابقة سطر لا يحتوي على السلسلة “42”، وطباعتها على الغلاف، والانتقال إلى السطر التالي. يتم إنجاز هذه المهمة بسهولة من خلال إرجاع متكرر على جميع كائنات المطابقة.

يتطابق نمط التعبيرات العادية '^((?!42).)*$' مع السطر بأكمله من الموضع الأول '^' إلى الموضع الأخير '$'.

ليست هناك تعليقات:

إرسال تعليق

😂11 مكتبة بايثون ممتعة لجعل يومك أفضل☀️

  في هذه المقالة سأقدم لك 11 مكتبة استمتعت باللعب بها وفكرت في مشاركتها معك.