الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

التعبيرات المنتظمة

بدأه ahmed_youssef في 7 ديسمبر 2010 · 7 رد · 2,018 مشاهدة · في لغة Python
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

Rockstar's Guide to RE

هنتكلم فى موضوع شيق "نسبيا" وهو التعابير المنتظمة Regular expressions واختصارا regex او regexp

ونستخدم ذلك التعبير كصورة مجردة للتعبير عن نص معين

سبب الأهمية

البحث عن مقطع معين بصورة معينة .. على سبيل المثال البحث عن الروابط او الصور فى صفحة ويب معينة وربما امكانية تحديث ذلك المقطع بإستبدال جزء من العنوان وحتي ربما التأكد من صحة نص معين ك أي بي او ايميل او موقع انترنت

قبل تنفيذ اي مثال تأكد من استدعاء وحدة re

import re

الفئات

الفئة بحرف صغير small تعبر عن الفئة بحرف capital تعبر عن نفي الفئة مثل

\d تعبر عن رقم

\D تعبر عن اي شئ غير الرقم

\w تعبر عن كلمة اى من الأحرف كبيرة او صغيرة بالإضافة للأرقام بالإضافة ل _

\W تعبر عن اي شئ غير الكلمة

\s تعبر عن مسافة وهى عبارة عن اي من ال \n أو \t او " “ او \r او غيرها

\S اي شئ غير المسافة

re.match (pat, string, flags=0)

>>> re.match("[0123456789]", "1") 
<_sre.SRE_Match object at 0xb757a170>

هنا فى ال pat وضعنا النمط او وهو [0123456789] اى ان النمط يعبر احد العناصر بين ال [ ] فإذا كان النص احدهم فينتج لنا وجود match

>>> re.match("[0-9]", "1") 
<_sre.SRE_Match object at 0xb7811d40> 

>>> re.match("[0-5]", "6")

بالطبع استنتجت الناتج هو لاشئ لأن 6 لاتقع فى مدي التعبير للنمط وهو من 0 ل 5

هنا نفس السابق ولكن كإسلوب مختصر لكتابة النمط [0-9] اى ان النمط عبارة عن رقم من 0 ل 9

نستطيع ايضا التعبير عنها بالفئة \d اختصارا ل digit بدل من [0-9]

>>> re.match("[a-z]", "c") 
<_sre.SRE_Match object at 0xb7811d40>

نفس الفكرة السابقة هل يقع النص مابين مدي الحروف a-z او لأ

>>> re.match("[A-Z]", "c") 

>>> re.match("[^a]", "a") 
>>> re.match("[^a]", "b") 
<_sre.SRE_Match object at 0xb77f3cd0>

هنا استخدام ^ تعني اي شئ ماعداها

النقطة .

النقطة كنمط تعبر عن كل شئ ماعدا الأسطر الجديدة \n الا اذا حددت فى ال flags القيمة re.DOTALL

>>> re.match(".", "c") 
<_sre.SRE_Match object at 0xb77f3cd0> 
>>> re.match(".", "11") 
<_sre.SRE_Match object at 0xb7811d40> 
>>> re.match(".", " ") 
<_sre.SRE_Match object at 0xb7811d40> 
>>> re.match(".", "\n") 
>>> re.match(".", "\n", re.DOTALL) 
<_sre.SRE_Match object at 0xb77f3cd0>

تعبير رمادي

>>> re.match("gr[ea]y", "grey") 
<_sre.SRE_Match object at 0xb757a170> 
>>> re.match("gr[ea]y", "gray") 
<_sre.SRE_Match object at 0xb77f3cd0> 
>>> re.match("gr[ea]y", "grly")

هنا التعبير gr[ea]y يعني النمط عبارة عن حرف g و r واي من e او a وليس كلاهما متبوعا بحرف y

الآن نريد ان نعلم مالذي تم الmatch عليه

قصة حياة Match

ال match عبارة عن كائن من sre_MATCH بيعبر عن ماتطابق من النص مع النمط

>>> m=re.match("gr(e|a)y","grey") 

>>> m

<_sre.SRE_Match object at 0xb77a44e0>

هنا نجد كائن match عائد من مكوناته group وهي وظيفة تعبر عن النص المتطابق اذا مررت لها القيمة 0 تجد الناتج كل النص بما ان حدث تطابق واذا مررت لها ترتيب index فهو ماتطابق داخل الأقواس مثل من تطابق هل e او a فى المثال السابق

>>> m.group(0)

'grey'

>>> m.group(1)

'e'

طيب انا ممكن اتلخبط مع الترتيبات .. هل ممكن اسمي مجموعة ما داخل ال match ? بالطبع!

كائن ال match بيديلك ميزة استخدام dict للحصول على المجموعة بالإسم وتمسي named group

>>> m=re.match("gr(?P<char>e|a)y","grey") 

>>> m.groupdict()

{'char': 'e'}

>>> m=re.match("gr(?P<char>[ae])y","grey") 

>>> m.groupdict()

{'char': 'e'}


>>> m.groupdict().get("char")

'e'

وتوفر لك ايضا وظيفة span وهي تعيد لك بداية ونهاية كل مجموعة متطابقة سواء النص بأكمله او مجموعة معينة داخله

>>> m.span(1)

(2, 3)

>>> m.span()

(0, 4)

نعم span عبارة عن ناتج وظيفتي start و end على مجموعة معينة

بداية ونهاية لتحديد بداية ونهاية التطابق استخدم ^ لتحديد البداية و $ لتحديد النهاية

>>> re.match("^real madrid$", "real madrid")

<_sre.SRE_Match object at 0xb779dbf0>

>>> re.match("^real madrid$", " real madrid")

>>> re.match("^real madrid$", "real madrid ")

مالعدد المطلوب؟

احيانا نريد مثلا المطابقة على 5 ارقام او عدد مابين 2 ل 8 لاأكثر ولاأقل او ربما اي عدد من الأرقام!

الحل عبر معاملات الزيادة

{m}

بعدد مرات m
>>> m=re.match("a{3}","aaaaaa")

>>> m

<_sre.SRE_Match object at 0xb779dc28>

>>> m=re.match("a{3}","ab")

>>> m

>>>

{m, n}

 بعدد اقل من المرات m وعدد اكبر n
>>> m=re.match("a{3,5}","aa")

>>> m

>>> re.match("a{3,5}","aaaaa")

<_sre.SRE_Match object at 0xb779dbf0>

+

بأي عدد على الأقل 1

>>> re.match("a+","b")

>>> m=re.match("a+","aaaaa")

>>> m

<_sre.SRE_Match object at 0xb779dbf0>

*

اى عدد على الأقل 0

>>> re.match("a*","b")

<_sre.SRE_Match object at 0xb779dbf0>

>>> re.match("a*","aaa")

<_sre.SRE_Match object at 0xb779dc60>

?

المطابقة ب 0 او 1 على الأكثر

>>> re.match("ba?","ba")

<_sre.SRE_Match object at 0xb779dbf0>

>>> re.match("ba?","bad")

<_sre.SRE_Match object at 0xb779dc60>

بلاش جشع!

>>> s="SOME BOLD TEXT"

>>> m=re.match("\[.+\]", s)

>>> m

<_sre.SRE_Match object at 0xb779dc60>

>>> m.group()

'SOME BOLD TEXT'

لاحظ المشكلة انها فتحت على الآخر واخدت لحد اخر قفلة قوس لكننا عايزين اول جزئية مثلا فالحل اننا نقلل الجشع لأن معاملات + و * جشعة بطبيعتها فبتاكل فى السلسلة على قد ماتقدر

>>> m=re.match("\[.+?\]", s)

>>> m.group()

''

فبعد المعامل نضع علامة استفهام لنخليها راضية وغير جشعة :D

مثال

SOME BOLD TEXT

عايزين نستخلص البداية والنهاية والمحتوي

بدأنا ب

>>> m=re.match("\[(?P<bbcode>.+?)\]", s)

>>> m.groupdict('bbcode')

{'bbcode': 'b'}

جيد كبداية ولكننا لم نحصل على باقي المطلوب النهاية والمحتوي

>>> m=re.match("\[(?P<bb>.+?)\](?P<text>.+)", s)

>>> m.group(2)

'SOME BOLD TEXT'

الآن جيد لدينا جروب بإسم text تعبر عن الباقي (محتوي ونهاية) وهو ليس المطلوب اذا يجب ان نستثني شكل النهاية منه نجد ان النهاية تكون بادئة ب [/ ثم اسم الكود ثم غلق القوس ]

>>> m=re.match(r'\[(?P<bb>\w+)\](?P<text>[^[][\w\s]+)\[\/(?P=bb)\]', s)

>>> m.groups()

('b', 'SOME BOLD TEXT')

تستطيع بدل استخدام (?P==bb ) ان تستخدم backref مثلا \1 وهي تعني اول مجموعة تم التقاطها captured وهنا هي bb

المقطع التالي مأخوذ من django/forums/fields.py

url_re = re.compile(
    r'https?://' # http:// or https://
    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
    r'localhost|' #localhost...
    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
    r'(?::\d+)?' # optional port
    r'(?:/?|/\S+)', re.IGNORECASE)

اذا هتستخدم النمط اكثر من مرة فقم بإستخدام re.compile واستخدم وظائف match و search منه لأداء افضل

هنا مثال للتأكد على الرابط المعطي سليم او لأ

re.IGNORECASE من ال flags وتعني تجاهل حالة النص المستخدم للمطابقة

>>> url_re = re.compile(

...     r'https?://' # http:// or https://

...     r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...

...     r'localhost|' #localhost...

...     r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip

...     r'(?::\d+)?' # optional port

...     r'(?:/?|/\S+)', re.IGNORECASE)

>>> url_re

<_sre.SRE_Pattern object at 0x9575000>

>>> url_re.match("hasdasd")

>>> url_re.match("http://programming-fr34ks.net")

<_sre.SRE_Match object at 0xb74f5598>

الآن لنعمل بعض البحث قليلا من خلال re.search

لدينا نص به بعض الجمل بالإضافة لبعض عناوين المواقع التي نريد استخلاصها

>>> s2

'hello http://programming-fr34ks.net some extra http://ahmedyoussef.wordpress.com more more '

اذا استخدمنا search فانه يعيدلنا اول match

>>> m=url_re.search(s2)

>>> m

<_sre.SRE_Match object at 0xb74f5608>

>>> m.group()

'http://programming-fr34ks.net'

اذا استخدمنا findall فستقوم بإعادة قائمة بها كل الكائات المتطابقة

>>> url_re.findall(s2)

['http://programming-fr34ks.net', 'http://ahmedyoussef.wordpress.com', '']

finditer نفس الشئ ولكن تعيد لنا iterator

الوظيفة split تقوم بتقسيم نص معين بناء على نمط وفى الغالب التقسيم على الأسطر الجديدة

الوظيفة sub, subn لاستبدال نص مطابق لتعبير منتظم فى نص ما بنص آخر

موضوعات مثل negative/positive lookahead/lookbehind خارج تغطية الموضوع

نصيحة الكاتب: استخدم http://pyparsing.wikispaces.com/ اذا تعقد الموضوع فالتعابير المنتظمة اذا تعقدت هتكره نفسك :D

للمزيد

http://docs.python.org/library/re.html

اي خطأ فى اي تعبير منتظم نرجو المعذرة :lol:

تم تعديل هذه المشاركة بواسطة ahmed_youssef في 7 ديسمبر 2010 في 03:35

8
(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#2

جميل اخي احمد أفادني الدرس كثيرا

خصوصا أنك بدأت تكتب باللغه العربية الفصحى وبأسلوب أكثر شموليه وتعبير

صراحه كتابك الخاص بالبايثون جميل ولكن المشكله اللتي واجهتني فيه 1- التعبيير في الكتابه وعدم الفصاحه فيه 2- الإختصار الشديد بالامثله وعدم شرح كل الجوانب في الأمثله

أعتذر عن الخروج عن الموضوع ولكن جمالية الموضوع جعلني اتمنى ان تكون سابق المواضيع بنفس صيغتها

--------------

ارجوا منك توضيح بعض النقاط بالموضوع فلم استوعبها بشكل جيد

>>> m=re.match("gr(?P<char>e|a)y","grey") 

>>> m.groupdict()

{'char': 'e'}

لم افهم بهذا الجانب

?P<char>e|a

ماذا تعني p وما فائدتها و <char> وفائدتها وعلامة الإستفاهم اللتي سبقتهم وما الغايه منها؟

----------------

m=re.match(r'\[(?P<bb>\w+)\](?P<text>[^[][\w\s]+)\[\/(?P=bb)\]', s)

الكود أصبح طلاسم هنا :lol:

هل يمكنك تقسيم الكود لأجزاء وكتابة وظيفة كل جزء :wacko:

وشكرا جزيلا لك :)

#3

الكتاب لسه تحت التنقيح اضافة وحذف وتعديل .. ربنا يسهل :(

ماشي خلينا واحدة واحدة

1- ال capturing group هي اي نمط موضوع بين قوسين ( )

>>> m=re.match("gr(e|a)y", "grey")
>>> m
<_sre.SRE_Match object at 0xb77fd520>
>>> m.groups()
('e',)
>>> m.group(0) #full match
'grey'
>>> m.group(1) #first group
'e'

لاحظ اننا نقدر نوصل ليها عن طريق m.group(1) ولكن اذا اردنا ان نسند ليها اسم فساعتها بيتحول اسمها ل named capturing group اي نقدر نوصل ليها ايضا بالإسم فاستخدام

(?P<name> )

يجعلنا نسند اسم لل group

هنا وليكن الإسم هنسميه char او letter او اللى يريحك

>>> m=re.match("gr(?P<letter>e|a)y", "grey")
>>> m
<_sre.SRE_Match object at 0xb77fd7e0>
>>> m.groups()
('e',)
>>> m.groupdict()
{'letter': 'e'}

اما فى اعادة استخدام تلك ال group فى مكان اخر بالنمط فإما اعادة كتابتها مرة اخري او استخدام backref (ترتيب الgroup مثلا \1 ) او استخدام اسم الجروب وذلك عن طريق (?P=groupname) وقيمتها كما فى المثال التالي

>>> reg=re.compile(
...     r'\[(?P<bb>\w+)\]' #start
...     r'(?P<text>[^[][\w\s]+)' #text
...     r'\[\/(?P=bb)\]' #end
...     )
>>> reg.match(s)
<_sre.SRE_Match object at 0xb779ba40>
>>> m=reg.match(s)
>>> m.groups()
('b', 'BOLD TEXT IN HERE')
>>> m.groupdict()
{'text': 'BOLD TEXT IN HERE', 'bb': 'b'}

هو نفس المثال بالأعلي ولكن بعد توضيب لتسهيل القراءة

انشئنا مجموعتين مجموعة تعبر عن ال bbcode وسمينها bb وبالتأكيد هي هتكون قيمة كود الأغلاق

  r'\[\/(?P=bb)\]' #end

والمجموعة الثانية

 r'(?P<text>[^[][\w\s]+)' #text

تعبر عن المحتوي مع تلافي وجود بداية قوس الأغلاق بس كدا

فبإختصار

(?P<groupname> ...)

تقوم بوضع اسم groupname للgroup

و

(?P=groupname)

تقوم بوضح محتوي ال مجموعة المسماة groupname بمكانها بدلا من اعادة كتابتها

\num

نفس عمل السابقة ولكن تستبدل بناء على ترتيب المجموعة

مثلا

>>> reg=re.compile(
...     r'\[(?P<bb>\w+)\]' #start
...     r'(?P<text>[^[][\w\s]+)' #text
...     r'\[\/\1\]' #end
...     )

اما عن

(?

مع ال P فهي تعني ان التالي يجب ان يكون معرف بايثوني سليم سواء عند التسمية او عند الإستدعاء

يوجد لها حالات اخري اضافية

2
(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#4

ربنا يبارك فيك

الحين اتضحت الصوره , كنت اشاهد إستعداء المكتبه في العديد من سكربتات البايثون

دون ان افهم طريقة إستخدامها

أشكرك مره أخرى ولكن يهمني أنك تعرف انني احد اللي يدعي لك في ظهر الغيب في كل موضوع تكتبه حتى لو ما علقت عليه

واصل اخي فبايثون العربيه أرتبطت بأسمك :lol:

#5

بارك الله فيك :)

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

#7

هل يمكنني أستخدام التعبيرات المنتظمة في عمل خاصية patched download

يعني لو أدخل المستخدم علي سبيل المثال رابط كهذا

http://www.example.com/files/[001:009]-test.zip

هل يمكن تحويلها إلي

http://www.example.com/files/001-test.zip
http://www.example.com/files/002-test.zip
http://www.example.com/files/003-test.zip
...
...
...
http://www.example.com/files/009-test.zip
#8

الأسلوب دا ممكن لفلترة الروابط في صفحة معينة لكن لاأظن عمل فرد لل pattern ممكن

بص flashgot كدا

ss4.png

فمثلا منطقي يكون الرابط بالشكل دا

http://www.example.com/files/00[1:9]-test.zip

ويكون [1:9] دي تتحول ل range (وربما متقدمة لو حروف مثلا تجيب قيمتها)

تم تعديل هذه المشاركة بواسطة ahmed_youssef في 24 مايو 2011 في 00:25

(map share people)

فضلا لاتقم بمراسلتي من أجل أسئلة لها أقسامها في المنتدى حتى تعم الفائدة على الجميع وللحصول على إجابات أفضل من أعضاء أكثر خبرة.
Weblog
@bitbucket
@xmonader

مواضيع مشابهة