این درس در ادامه درس قبل «عبارات با قاعده یا Regular Expression» میباشد و به شرح برخی از تابعهای کاربردی موجود در ماژول re از کتابخانه استاندارد زبان برنامهنویسی پایتون میپردازد. پیش از مطالعه این درس میبایست حتما درس قبل را نیز مطالعه کرده باشید.
تابع search به دنبال اولین انطباق pattern در string میگردد، در صورت موفقیت یک شی Match [اسناد پایتون] و در غیر این صورت None برمیگرداند [اسناد پایتون]:
>>> importre>>>>>> match=re.search('Py...n','Python is great')>>>>>> type(match)<class 're.Match'>
اجازه بدهید یادآوری کنیم که دو نمونه کد زیر عملکردی معادل یکدیگر دارند:
>>> pattern=re.compile('Py...n')>>> match=pattern.search('Python is great')
این متد از شی Match، گروه (های) تطبیق داده شده بر اساس الگو مورد نظر را برمیگرداند. این متد میتواند یک یا چند آرگومان عددی دریافت کند که معرف اندیس گروه مورد نظر میباشد. در حالت فراخوانی بدون آرگومان تمامی گروههای تطبیق داده شده به صورت یک مقدار رشته برگردانده میشود و در صورتی تنها یک مقدار به آن ارسال گردد، گروه تطبیق داده شده متناظر با آن اندیس (شمارش اندیسها از یک است) در قالب یک شی رشته برگردانده میشود و در صورتی که بیش از یک اندیس به عنوان آرگومان ارسال گردد یک شی توپِل محتوی گروههای تطبیق داده شده برگردانده خواهد شد. چنانچه آرگومان ارسالی عددی منفی باشد یا اندیسی بالاتر از تعداد گروههای تطبیق داده شده باشد، یک استثنا IndexError رخ خواهد داد:
>>> match=re.search("(\w+) (\w+)","Isaac Newton, physicist")>>> match.group()# The entire match'Isaac Newton'>>> match.group(0)# The entire match'Isaac Newton'>>> match.group(1)# The first parenthesized subgroup.'Isaac'>>> match.group(2)# The second parenthesized subgroup.'Newton'>>> match.group(1,2)# Multiple arguments give us a tuple.('Isaac', 'Newton')>>> match.group(3)Traceback (most recent call last):
File "<stdin>", line 1, in <module>IndexError: no such group
فراخوانی بدون آرگومان (یا ارسال آرگومان صفر - مقدار پیشفرض) این متد، تمام متن تطبیق داده شده را برمیگرداند:
>>> pattern=re.compile('Py...n')>>> match=pattern.search('Python is great')>>> match.group()'Python'>>> match.group(0)'Python'
این متد تمام گروههای تطبیق داده شده بر اساس الگو مورد نظر را در قالب یک شی توپِل برمیگرداند. این متد میتواند یک آرگومان بپذیرد که معرف مقدار پیشفرض برای جایگذاری گروههایی است که در رشته ورودی تطبیق داده نشدهاند، در حالت عادی (بدون ارسال آرگومان) این مقدار برابر با None است:
>>> match=re.search("(\d+)\.?(\d+)?","24")>>> match.groups()# Second group defaults to None.('24', None)>>> match.groups('0')# Now, the second group defaults to '0'.('24', '0')
>>> pattern=re.compile('Py...n')# The pattern is without grouping>>> match=pattern.search('Python is great')>>> match.groups()()
این متد نیز همانند متد groups یک پارامتر اختیاری دارد که در صورت ارسال آرگومان به آن به جای مقدار پیشفرض None برای حاصل عدم تطابق گروههای موجود در الگو قرار میگیرد:
این متد حاصل انطباق را در قالب template جایگذاری کرده و یک شی رشته جدید برمیگرداند. قالب در اینجا یک رشته است که در آن میتوان به حاصل انطباق گروهبندیهای موجود در الگو ارجاع داد به این صورت کرد که میتوان گروههای بینام موجود در الگو را با استفاده از ارجاع عددی به شماره اندیس آنها به مانند 1\، 2\ یا <g<1\ و گروههای بانام را با استفاده از نام گروه به مانند <g<name\ در قالب موجود جایگذاری کرد. Escape characterهای موجود در قالب به کاراکترهای مناسب خود در متن خروجی تبدیل میشوند و از نسخه 3.5 پایتون گروههایی که هیچ انطباقی نداشتهاند با هیچی (empty string) جایگذاری میشوند:
# \1, \2 and \3 are all valid escape characters
\1# (U+0001 or 0x01) stands for the ascii start-of-heading character
\2# (U+0002 or 0x02) stands for the ascii start-of-text character
\3# (U+0003 or 0x03) stands for the ascii end-of-text character
توجه
در نمونه کد بالا، خروجی نخستین استفاده از متد expand متناسب با انتظار نیست، دلیل هم مربوط به وجود کاراکترهایی با \ است (escape characters) که باعث بروز اخلال در تحلیل رشته قالب شده است. بهتر است همیشه در این مواقع از قوانین raw string پیروی نماییم: استفاده از \\ به جای \ (همانند n\\) یا قرار دادن یک کاراکتر r یا R در ابتدای رشته (همانند 'r'\n). در این صورت کاراکترهایی همچون newline یا n\ در رشته، معنای خود را از دست میدهند. (یادآوری از درس هفتم)
در واقع مفسر پایتون پیش از قراردادن متن مورد نظر ما در قالب یک شی رشته (string) در حافظه (memory) آن را تحلیل و مقادیر متناسب با کاراکترهای \ را در آن جایگذاری میکند که این کار ممکن است در هنگام استفاده ماژول re از آن شی رشته اخلال ایجاد کند. استفاده از raw string باعث میشود مفسر پایتون متن مورد نظر را بدون تغییر در حافطه قرار دهد.
همیشه در هنگام کار با RegEx (نه فقط در زبان پایتون!) مواظب escape characters یا همان backslash characters باشید. تا این لحظه برای جلوگیری از پیچیدگی در مثالهای ارائه شده مبحث RegEx از قرار دادن raw string صرف نظر شده بود اما از آنجا که الگوهای RegEx پر از \ است همواره میبایست به لزوم استفاده از raw string فکر کنیم.
متن رشته خروجی (تطبیق یافته بر اساس الگو مورد نظر) را در نظر بگیرید، متد start اندیس شروع این متن از رشته ورودی و متد end اندیس نقطه پایان را برمیگرداند. این دو متد میتوانند یک آرگومان اختیاری نیز دریافت کنند که معرف اندیس یک گروه مشخص در الگو میباشد، با ارسال این آرگومان نتایج بر اساس تکه متن تطبیق داده شده با آن گروه برگردانده خواهد شد:
این متد یک شی توپِل دوتایی از خروجی دو متد start و end را بر میگرداند و همانند آنها نیز یک آرگومان اختیاری دارد - نمونه خروجی:
(m.start(group),m.end(group))
>>> match=re.search(r"(\d+)\.(\d+)","24.1632")>>> match.span()(0, 7)>>> match.span(1)(0, 2)>>> match.span(2)(3, 7)>>> match.span(3)Traceback (most recent call last):
File "<stdin>", line 1, in <module>IndexError: no such group
هنگام استفاده از تابع match، از همان ابتدای متن مورد نظر، میبایست تطابق با الگو صورت پذیرد (حتی در متنهای چند سطری) ولی تابع search انجام انطباق را در هر جایی از متن دنبال میکند.
هنگام استفاده از نشانه re.MULTILINE در تابع search، کاراکتر ^ در الگو از معنای ابتدای متن به معنای ابتدای هر سطر تغییر میکند (درس قبل) ولی از نظر تابع match وجود کاراکتر ^ در الگو همواره به معنی ابتدای متن میباشد (نه هر سطر):
این تابع (fullmatch) چنانچه تمام string با pattern انطباق داشته باشد یک شی Match و در غیر این صورت None برمیگرداند [اسناد پایتون] - این تابع از پایتون نسخه 3.4 به بعد در دسترس است:
این تابع (findall) حاصل تمام انطباقهای ممکن pattern در string را در قالب یک لیست از رشتهها (نتایج) برمیگرداند [اسناد پایتون]:
>>> importre>>> string="My number is 123456789 and my friend's number is 987654321">>> results=re.findall(r'\d+',string)>>> type(results)<class 'list'>>>> print(results)['123456789', '987654321']
تابع findall از سمت چپ string شروع به دنبال انطباق pattern در آن میگردد و نتایج را به ترتیب برمیگرداند. اگر الگو (pattern) شامل گروه باشد فقط نتایج مربوط به انطباق گروه را برمیگرداند و نه تمام الگو را:
خروجی این تابع (finditer) یک شی iterator (شی تکرارکننده - درس نهم) است و حاصل هر بار پیمایش آن یک شی Match میباشد که همانند تابع findall از سمت چپ string شروع به دنبال انطباق pattern در آن میگردد و نتایج را به ترتیب برمیگرداند. [اسناد پایتون]:
>>> importre>>> string="My number is 123456789 and my friend's number is 987654321">>> result=re.finditer(r'\d+',string)>>> type(result)<class 'callable_iterator'>>>> result.__next__()<re.Match object; span=(13, 22), match='123456789'>>>> result.__next__()<re.Match object; span=(49, 58), match='987654321'>>>> result.__next__()Traceback (most recent call last):
File "<stdin>", line 1, in <module>StopIteration
این تابع (sub) حاصل انطباقهای ممکن pattern در string را در repl جایگذاری میکند. این تابع همچنین دو پارامتر اختیاری دارد (flags و count)، پیشتر در مورد flags صحبت کردیم (که از نسخه 3.1 پایتون به این تابع اضافه شده است) و count نیز بیانگر ماکزیمم تعداد انطباقی است که میخواهیم در repl جایگذاری شود - این مقدار میبایست یک عدد مثبت باشد و مقدار صفر (مقدار پیشفرض) برای آن به معنی هر تعداد (نامحدود) خواهد بود. پارامتر repl در این تابع میتواند از نوع رشته یا تابع باشد، ابتدا حالت رشته را بررسی میکنیم [اسناد پایتون]:
متد expand از شی Match که در ابتدای این درس مطرح شد را بیاد بیاورید، بدیهی است که pattern میتواند شامل گروهبندی نیز باشد، در این شرایط آنچه از قوانین موجود در پارامتر template متد expand گفته شد در repl (در حالتی که یک شی رشته است) نیز صدق میکند:
الگو مورد استفاده برای متن مثال بالا یک Zero-length Match است (درس قبل) - [regex101@ تست آنلاین]
نکته
چنانچه تابع sub هیچ انطباقی از pattern در string پیدا نکند، مقدار string را بدون تغییر برمیگرداند:
>>> re.sub(r'\d','-','abc@xyz')# Without matching'abc@xyz'>>> re.sub(r'\d','-','abc@123')'abc@---'
گفتیم پارامتر repl در این تابع میتواند از نوع تابع باشد. در این صورت sub در هر بار انطباق تابع repl را فراخوانی میکند و شی Match مربوط را به آن ارسال میکند:
>>> importre>>> defmask_numbers(match):... string=match.group(0)# The matching string...... # string.isdigit() returns True if all characters in string are digits... ifstring.isdigit():... return'_'*len(string)... else:... returnstring...>>>>>> re.sub(r'\w+',mask_numbers,'Perl.1987.Python.1991.Ruby.1995')'Perl.____.Python.____.Ruby.____'>>> re.sub(r'\w+',mask_numbers,'My ID is 123.45679 and your ID is 98521.2')'My ID is ___._____ and your ID is _____._'
>>> re.sub(r'\d+',lambdamatch:'_'*len(match.group(0)),'Perl.1987.Python.1991.Ruby.1995')'Perl.____.Python.____.Ruby.____'>>> re.sub(r'\d+',lambdamatch:'_'*len(match.group(0)),'My ID is 123.45679 and your ID is 98521.2')'My ID is ___._____ and your ID is _____._'
lambda در درس سیزدهم بررسی شده است.
یادآوری میشود که دو نمونه کد زیر عملکردی معادل یکدیگر دارند:
عملکرد این تابع (subn) همانند تابع sub است. تنها تفاوت در خروجی آنهاست، تابع subn یک شی توپِل محتوی نتیجه و تعداد عملیات جایگذاری را برمیگرداند [اسناد پایتون]:
این تابع (split) محتوای متن string را بر اساس الگو pattern جدا (split) میکند و خروجی آن یک شی لیست از رشتهها خواهد بود. این تابع همچنین علاوه بر پارامتر flags (که از نسخه 3.1 پایتون به این تابع اضافه شده است) یک پارامتر اختیاری دیگر نیز با نام maxsplit دارد که تعیین کننده ماکزیمم تعداد جداسازی خواهد بود - این مقدار میبایست یک عدد مثبت باشد و مقدار صفر (مقدار پیشفرض) برای آن به معنی هر تعداد (نامحدود) خواهد بود. [اسناد پایتون]:
همانطور که مشاهده میشود، خروجی شامل دو رشته خالی در ابتدا و انتها میباشد. در مواقعی که جداکننده (delimiter) در نقاط ابتدایی و پایانی متن قرار دارد میبایست بروز همچین نتیجهای را پیشبینی نمایید.
چنانچه در مسئله شما قرار گرفتن جداکننده در خروجی مطلوب نیست میتوانید از طرح non-capturing پرانتزها (درس قبل) استفاده کنید:
You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.