Mehdi Asgari
چهارشنبه 16 تیر 1389, 13:53 عصر
دیروز داشتم روی یک پروژۀ مرتبط با کرنل ویندوز کار می کردم که قرار بود یه سری کارا رو خودکار کنم (قادر به ذکر جزییات نیستم)
قسمتی از پروژه نوشتن یک پارسر برای یه سری ساختار های کوفتی کرنل بود که بعد از پارس کردن ، یه سری پارامتر generate کرده و تحویل یه برنامه ای بدم. بالطبع برنامه نویسی کرنل فقط جای سی هست (حتی سی پلاس پلاس هم نه، فقط سی. بله دیگه ، ای مگس عرصۀ سیمرغ و از این چیزا)؛ تصمیم گرفتم حداقل پارسر رو با یه زبان high level تر نوشته و در وقت صرفه جویی کنم. مطمئنا وقتی صحبت از high level میشه اول به پایتون فکر می کنم، تصمیم گرفتم از Regex استفاده کنم (پیچیدگی کار طوری بود که نمی تونستم از parser generator ها استفاده کنم، چون در واقع گرامری وجود نداشت؛ به هر حال کد ویندوزه و هزاران سورپرایز و باید تمام حالات ممکن هندل می شد). Regex ای که نوشتم یک روز کاری از وقتم رو گرفت و پیچیده ترین رجکسی هست که تا به حال نوشتم. یه جای کار متوجه چیز عجیبی شدم: وقتی یک named group بیش از یک دفعه match میشه ، فقط آخرین نمونۀ اون ذخیره شده و قابل دسترسی هست.
تکه ای از Regex ام:
(\*?(?<names>\w+))
اینجا names یک named group هست (کل این تکه ، خودش جزئی از یک گروه بزرگ تره)؛ اگه 5 کلمه توسط این گروه match بشن ، فقط آخری رو می تونیم بهش دسترسی داشته باشیم.
سرچ کردم و ظاهرا این رفتار رجکس پایتون هست و راهی برای دسترسی به match های قبلی نداریم (شاید بشه کلی کد زد و راهی پیدا کرد که بشه این کار رو کرد ولی پایتون تا جایی که من می دونم راه مستقیمی برای این کار نداره)
تصمیم گرفتم از دات نت استفاده کنم ؛ در دات نت چیزی داریم به نام Capture ؛ حالا من میگم تمام capture های یک گروه خاص رو بهم بده؛ در نتیجه تمام اون 5 کلمه رو خواهم داشت.
این دو مثال رو ببینید تا متوجه بشید چی میگم (این رجکس فقط برای مثاله و کلی ساده اش کردم. استفاده از اون در کد واقعی اصلا توصیه نمیشه. در ضمن برای مثال سادۀ پایین میشه رجکس ساده تری نوشت)
اول پایتون
import re
contents = ''' IN DWORD mehdi,
OUT UNICODE_STRING ali '''
regex = re.compile ('((IN)?\s*(OUT)?\s* ([a-zA-Z_]+) (\*?(?P<names>\w+))\s*,?)+')
matchobj = regex.search(contents)
if (matchobj):
print matchobj.group('names')
خروجی: ali
و حالا دات نت: با استفاده از Capture هم mehdi مچ میشه هم ali (از اف شارپ استفاده کردم)
open System.Text.RegularExpressions
let regex = Regex(@"((IN)?\s*(OUT)?\s* ([a-zA-Z_]+) (\*?(?<names>\w+))\s*,?)+")
let contents = "IN DWORD mehdi,\
OUT UNICODE_STRING ali "
let matches = regex.Matches contents
for c in matches.[0].Groups.["names"].Captures do
printfn "%s" c.Value
دوستان، نظر ؟
قسمتی از پروژه نوشتن یک پارسر برای یه سری ساختار های کوفتی کرنل بود که بعد از پارس کردن ، یه سری پارامتر generate کرده و تحویل یه برنامه ای بدم. بالطبع برنامه نویسی کرنل فقط جای سی هست (حتی سی پلاس پلاس هم نه، فقط سی. بله دیگه ، ای مگس عرصۀ سیمرغ و از این چیزا)؛ تصمیم گرفتم حداقل پارسر رو با یه زبان high level تر نوشته و در وقت صرفه جویی کنم. مطمئنا وقتی صحبت از high level میشه اول به پایتون فکر می کنم، تصمیم گرفتم از Regex استفاده کنم (پیچیدگی کار طوری بود که نمی تونستم از parser generator ها استفاده کنم، چون در واقع گرامری وجود نداشت؛ به هر حال کد ویندوزه و هزاران سورپرایز و باید تمام حالات ممکن هندل می شد). Regex ای که نوشتم یک روز کاری از وقتم رو گرفت و پیچیده ترین رجکسی هست که تا به حال نوشتم. یه جای کار متوجه چیز عجیبی شدم: وقتی یک named group بیش از یک دفعه match میشه ، فقط آخرین نمونۀ اون ذخیره شده و قابل دسترسی هست.
تکه ای از Regex ام:
(\*?(?<names>\w+))
اینجا names یک named group هست (کل این تکه ، خودش جزئی از یک گروه بزرگ تره)؛ اگه 5 کلمه توسط این گروه match بشن ، فقط آخری رو می تونیم بهش دسترسی داشته باشیم.
سرچ کردم و ظاهرا این رفتار رجکس پایتون هست و راهی برای دسترسی به match های قبلی نداریم (شاید بشه کلی کد زد و راهی پیدا کرد که بشه این کار رو کرد ولی پایتون تا جایی که من می دونم راه مستقیمی برای این کار نداره)
تصمیم گرفتم از دات نت استفاده کنم ؛ در دات نت چیزی داریم به نام Capture ؛ حالا من میگم تمام capture های یک گروه خاص رو بهم بده؛ در نتیجه تمام اون 5 کلمه رو خواهم داشت.
این دو مثال رو ببینید تا متوجه بشید چی میگم (این رجکس فقط برای مثاله و کلی ساده اش کردم. استفاده از اون در کد واقعی اصلا توصیه نمیشه. در ضمن برای مثال سادۀ پایین میشه رجکس ساده تری نوشت)
اول پایتون
import re
contents = ''' IN DWORD mehdi,
OUT UNICODE_STRING ali '''
regex = re.compile ('((IN)?\s*(OUT)?\s* ([a-zA-Z_]+) (\*?(?P<names>\w+))\s*,?)+')
matchobj = regex.search(contents)
if (matchobj):
print matchobj.group('names')
خروجی: ali
و حالا دات نت: با استفاده از Capture هم mehdi مچ میشه هم ali (از اف شارپ استفاده کردم)
open System.Text.RegularExpressions
let regex = Regex(@"((IN)?\s*(OUT)?\s* ([a-zA-Z_]+) (\*?(?<names>\w+))\s*,?)+")
let contents = "IN DWORD mehdi,\
OUT UNICODE_STRING ali "
let matches = regex.Matches contents
for c in matches.[0].Groups.["names"].Captures do
printfn "%s" c.Value
دوستان، نظر ؟