چند روز پیش (۲۷ شهریور) یه مدل جدید به اسم Jev از شرکت TypeSafe به OpenRouter اضافه شد. این مدل با ChatGPT و بقیه رفقاش یه فرق اساسی داره. متن نمینویسه! شما یه متن بهش میدید و یه سوال بله/خیر ازش میپرسید، اونم فقط یه عدد بین ۰ تا ۱ برمیگردونه که یعنی چقدر مطمئنه جواب «بله»ست.
من میخواستم ببینم این مدل میتونه جای regex رو بگیره یا نه. یعنی به جای اینکه یه الگوی عجیب غریب بنویسیم، ازش بپرسیم «این ایمیل درسته؟» و تمام. اومدم یه بنچمارک درست کردم که سرعت، هزینه و دقتش رو هم در حالت تک به تک و هم در حالت بچ (batch) با regex مقایسه کنم.
regex (عبارت منظم) به زبون آدمیزاد یه الگوئه که میگه یه متن باید چه شکلی باشه. مثلا وقتی توی یه سایت شماره موبایلتون رو وارد میکنید و میگه «شماره وارد شده صحیح نیست»، معمولا پشتش یه چیزی شبیه این نشسته :
re.match(r'^(\+98|0098|98|0)?9\d{9}$', "09121234567")
یعنی چی؟ یعنی اولش میتونه +98 یا 0098 یا 98 یا 0 باشه (یا هیچی)، بعدش حتما 9 و بعدش دقیقا ۹ تا رقم دیگه. به همین سادگی! این الگو ها رو معمولا کسی از اول نمینویسه و از اینترنت کپی میشن. من هم دقیقا همین regex های رایج رو برداشتم، یعنی همونایی که همه جا کپی شدن.
یه درخواست ساده به Jev این شکلیه :
requests.post("https://openrouter.ai/api/alpha/decisions", headers=headers, json={ "model": "~typesafe/jev-latest", "state": "[email protected]", "questions": { "email": {"type": "noul", "instructions": "Is the state exactly one syntactically valid email address?"} } }).json()
{'model': 'typesafe/jev-1.13-20260917',
'answers': {'email': {'type': 'noul', 'noul': 0.88}},
'usage': {'input_tokens': 283, 'output_tokens': 20, 'cost': 1.1886e-05}}state همون متنیه که میخوایم در موردش سوال بپرسیم و questions هم سوال هامونه (noul یعنی سوال بله/خیر). اون 0.88 یعنی Jev ۸۸ درصد مطمئنه که این یه ایمیل درسته. من هر جا عدد بالای ۰.۵ بود جواب رو «بله» در نظر گرفتم. قیمتش هم اینجوریه که هر ۱ میلیون توکن ورودی ۰.۰۴۲ دلاره و خروجی مجانیه. توکن هم یعنی تیکه های کوچیک متن که مدل ها با اون حساب میکنن، تقریبا اندازه یه کلمه یا کمتر. همین سوال بالا ۲۸۳ توکن شد، یعنی حدود ۰.۰۰۰۰۱۲ دلار.
دو جور آزمون گذاشتم :
۱. چک کردن درستی : یعنی یه متن رو بدیم و بپرسیم «این ایمیل درسته؟» یا «این تاریخ درسته؟». ۱۲ تا از الگو های رایج رو انتخاب کردم : ایمیل، آدرس سایت، IP، موبایل، کد ملی، تاریخ میلادی، تاریخ شمسی، کد رنگ (مثل #fff)، UUID، ساعت، رمز عبور قوی و «متن فقط فارسی». برای هر کدوم حدود ۴۴ تا نمونه ساختم که در مجموع شد ۵۳۴ تا. بعضیاش رو دستی نوشتم که عمدا تله داشته باشن (مثل [email protected] که دو تا نقطه پشت هم داره) و بقیه رو به صورت تصادفی ساختم.
۲. پیدا کردن توی پیام : یعنی یه پیام فارسی بدیم و بپرسیم «توش شماره موبایل هست؟»، «ایمیل هست؟» و «لینک هست؟». ۴۴ تا پیام نوشتم که بعضیاش آدم رو میپیچونن. مثلا «شمارهام ۰۹۱۲-۱۲۳-۴۵۶۷ است» یا «ali.rezaei ات جیمیل دات کام». ۴۴ تا پیام ضربدر ۳ تا سوال میشه ۱۳۲ تا سوال.
جواب درست نمونه های بخش اول رو با کد معمولی پایتون (نه regex) حساب کردم که مطمئن باشم درسته. جواب پیام ها رو هم دستی زدم. به Jev هم دقیقا همون قانونی که regex چک میکنه رو به زبون انگلیسی گفتم. مثلا برای ایمیل بهش گفتم نقطه نباید اول یا آخر اسم باشه و دو تا نقطه هم نباید پشت هم بیاد.
تک به تک یعنی هر بار یه نمونه بفرستیم و جوابش رو بگیریم. بچ یعنی یه جا ۱۰ یا ۱۰۰ یا ۱۰۰۰ تا نمونه رو با هم بفرستیم. مثل اینکه به جای اینکه ۱۰۰ بار تا سوپرمارکت برید و هر بار یه چیز بخرید، یه بار برید و ۱۰۰ تا چیز بخرید. چرا این مهمه؟ چون هر درخواست به Jev یه هزینه ثابت داره، درست مثل کرایه رفت و آمد تا سوپرمارکت. حدود ۲۷۰ تا توکن فقط خرج خود درخواست میشه، حالا چه یه نمونه توش باشه چه هزار تا.
نکتهای که وجود داره اینه که Jev خودش بچ نداره و هر درخواست فقط یه state (یعنی یه ورودی) میگیره. من اومدم چند تا نمونه رو گذاشتم توی یه JSON و برای هر کدوم یه سوال جدا پرسیدم :
state = { "rules": {"email": "A valid email address: ..."}, "items": {"i000": "[email protected]", "i001": "[email protected]"} } questions = { "i000": {"type": "noul", "instructions": "Is items.i000 a valid email address? Apply rules.email strictly."}, "i001": {"type": "noul", "instructions": "Is items.i001 a valid email address? Apply rules.email strictly."} }
فرض کنید یه فایل دارید با ۱ میلیون تا ایمیل یا شماره موبایل و میخواید ببینید کدوماش درسته. جدول زیر نشون میده هر روش چقدر طول میکشه و چقدر خرج داره. البته من ۱ میلیون تا رو واقعا به Jev ندادم. سرعتی که توی آزمون اندازه گرفتم رو برای ۱ میلیون حساب کردم :
| زمان برای ۱ میلیون | هزینه برای ۱ میلیون | |
|---|---|---|
| regex (روی یه هسته CPU) | ۰.۱۸ ثانیه | تقریبا صفر |
| Jev تک به تک، یکی بعد از دیگری | ۸ روز | ۱۶.۶ دلار |
| Jev تک به تک، ۱۶ تا همزمان | ۱۴ ساعت | ۱۶.۶ دلار |
| Jev، هر درخواست ۵۰۰ تا، ۱۰ درخواست همزمان | ۲۱ دقیقه | ۲.۲ دلار |
یعنی تو همون ۰.۶ ثانیهای که Jev به یه سوال جواب میده، regex حدود ۴.۷ میلیون تا نمونه رو چک کرده! اگه بخوام یه جور دیگه بگم، اگه regex برای چک کردن یه چیزی ۱ ثانیه وقت بذاره، Jev تک به تک ۵۴ روز وقت میذاره 🙂
البته انصافا از اون ۰.۶ ثانیه، حدود ۰.۵ ثانیهش رفت و برگشت اینترنته. من از ایران و با پروکسی به سرور های Jev توی آمریکا وصل میشدم. ولی حتی اگه شبکه رو کنار بذاریم، باز هم regex صدها هزار برابر سریعتره.
حالا بریم سراغ اینکه اندازه بچ چه تاثیری داره. هر بار N تا ایمیل تازه رو توی یه درخواست فرستادم (هر اندازه رو ۳ بار) و زمان جواب و هزینه رو نوشتم. جدول زیر نتیجهست :
| تعداد در هر درخواست | زمان جواب (ثانیه) | هزینه هر ۱۰۰۰ تا (سنت) | توکن برای هر نمونه |
|---|---|---|---|
| ۱ | ۰.۴۷ | ۱.۸۹ | ۴۵۰ |
| ۱۰ | ۰.۸۹ | ۰.۳۹ | ۹۲ |
| ۵۰ | ۰.۶۹ | ۰.۲۵ | ۶۰ |
| ۱۰۰ | ۱.۴۳ | ۰.۲۳ | ۵۶ |
| ۲۵۰ | ۳.۳۵ | ۰.۲۲ | ۵۲ |
| ۵۰۰ | ۵.۳۲ | ۰.۲۲ | ۵۱ |
| ۱,۰۰۰ | ۸.۹۶ | ۰.۲۱ | ۵۱ |
| ۲,۰۰۰ | خطا داد! | - | - |
همونطور که میبینید از ۱ تا ۵۰، هزینه حدود ۷.۵ برابر کم میشه ولی زمان جواب تقریبا عوض نمیشه. از ۱۰۰ به بعد هزینه دیگه خیلی کم نمیشه ولی زمان جواب پشت سر هم زیاد میشه، به ازای هر نمونه حدود ۹ میلیثانیه. ۲۰۰۰ تا رو هم کلا قبول نکرد و خطای max_tokens_exceeded داد. پس جای خوبش یه جایی بین ۵۰ تا ۱۰۰ تاست. دقتش هم توی بچ ۱۰۰۰ تایی هنوز ۹۸ درصد بود.
خب رسیدیم به سوال اصلی. جدول زیر نشون میده هر روش چند درصد جواب ها رو درست داده :
| regex رایج | regex با پیشپردازش | Jev با متن ساده | Jev با ورودی JSON | Jev بچ ۱۰ تایی | |
|---|---|---|---|---|---|
| چک کردن درستی ایمیل، تاریخ و … (۵۳۴ تا) | ۸۵.۰ | - | ۷۷.۹ | ۹۱.۸ | ۹۳.۴ |
| پیدا کردن شماره، ایمیل و لینک توی پیام (۱۳۲ تا) | ۸۲.۶ | ۹۷.۰ | ۱۰۰ | ۱۰۰ | ۹۹.۲ |
«regex با پیشپردازش» یعنی قبل از اینکه regex رو اجرا کنم، متن رو یکدست کردم : ارقام فارسی رو انگلیسی کردم، فاصله و خط تیره وسط عدد ها رو برداشتم و [at] و dot رو به @ و . تبدیل کردم. این کار فقط برای پیام ها معنی داره. دو ستون «Jev با متن ساده» و «Jev با ورودی JSON» هر دو تک به تک هستن و فرقشون رو پایینتر توضیح میدم.
نکته جالبش اینه که توی چک کردن درستی، regex رایج از Jev با متن ساده بهتر بود ولی از Jev با ورودی JSON بدتر. توی پیدا کردن شماره و ایمیل و لینک هم Jev هر ۱۳۲ تا سوال رو درست جواب داد.
البته اینم بگم که جواب درست بخش اول رو با کد معمولی پایتون حساب کرده بودم. پس اگه همون کد رو به جای regex استفاده کنید، طبیعتا ۱۰۰ درصد میشه 🙂 و هر بار چک کردن هم زیر ۳ میکروثانیه طول میکشه.
اولش متن رو همونجوری که بود به Jev میدادم و قانون رو توی متن سوال مینوشتم. یعنی state فقط خود متن بود. بعد دیدم اگه متن و قانون رو کنار هم توی یه JSON بذارم (همون شکلی که بالاتر برای بچ ساختم)، خیلی بهتر جواب میده. حتی وقتی فقط یه نمونه توش باشه! جدول زیر چند تا نمونه رو نشون میده. عدد ها احتمال «بله» هستن :
| متن | سوال | جواب درست | Jev با متن ساده | Jev با ورودی JSON |
|---|---|---|---|---|
| # fff | کد رنگ درسته؟ | نه | ۰.۷۴ | ۰.۰۲ |
| 9:05 | ساعت به شکل HH:MM هست؟ | نه | ۰.۹۳ | ۰.۰۲ |
| ali [email protected] | ایمیل درسته؟ | نه | ۰.۹۴ | ۰.۰۱ |
| [email protected] | ایمیل درسته؟ | نه | ۰.۸۸ | ۰.۰۱ |
| #FFFFFFFF | کد رنگ ۳ یا ۶ رقمی هست؟ | نه | ۰.۷۰ | ۰.۰۱ |
| 1405/06/30 | تاریخ شمسی واقعیه؟ | آره | ۰.۷۱ | ۰.۳۵ |
همونطور که میبینید با JSON خیلی بهتر شد ولی همه جا نه. ۳۰ شهریور ۱۴۰۵ (یعنی امروز!) رو با متن ساده درست گفت ولی با JSON گفت همچین تاریخی وجود نداره :/
این الگو ها رو هزاران نفر کپی کردن ولی ایراد های جالبی دارن :
| متن | regex چی گفت؟ | چرا غلطه؟ |
|---|---|---|
| [email protected] | ایمیل درسته | دو تا نقطه پشت هم مجاز نیست |
| 2026-02-30 | تاریخ درسته | فوریه ۳۰ روز نداره |
| 1405/07/31 | تاریخ درسته | مهر ۳۰ روزهست |
| 09۱۲۱۲۳۴۵۶۷ | شماره درسته | نصفش ارقام فارسیه. توی پایتون \d ارقام فارسی رو هم قبول میکنه! |
| 192.168.1.1\n | IP درسته | $ یه Enter آخر متن رو نمیبینه |
| میخواهم کتاب بخرم | متن فارسی نیست | نیمفاصله توی بازه \u0600-\u06FF نیست |
| کد پیگیری پرداختم 60379912345678 هست | شماره موبایل داره | وسط یه عدد ۱۴ رقمی، 9912345678 رو پیدا کرده |
راه حلش سخت نیست. به جای $ از fullmatch استفاده کنید، به جای \d بنویسید [0-9]، نیمفاصله (\u200c) رو به بازه حروف فارسی اضافه کنید و برای تاریخ و کد ملی چند خط کد بنویسید. regex به تنهایی نمیتونه بفهمه ۳۱ مهر وجود نداره یا رقم کنترل کد ملی درسته یا نه.
حتی با ورودی JSON هم چند جا کم آورد :
کد ملی : فرمول رقم کنترل رو کامل بهش دادم ولی بیشتر جواب هاش دور و بر ۰.۵ بود. یعنی عملا شیر یا خط انداخت. بهترین دقتش ۷۵ درصد بود.
تاریخ شمسی : علاوه بر ۳۰ شهریور، 1399/12/30 رو هم رد کرد، با اینکه بهش گفته بودم ۱۳۹۹ کبیسهست.
موبایل بدون صفر : 9121234567 طبق همون قانون درسته ولی Jev ردش کرد.
نیمفاصله : با اینکه صریحا گفته بودم نیمفاصله مجازه، چند تا از متن های فارسیِ نیمفاصلهدار رو رد کرد. یعنی دقیقا همون سوتی regex رو داد!
به زبون آدمیزاد، Jev معنی رو خوب میفهمه ولی حساب کتاب و شمردن کاراکتر کارش نیست.
اما توی پیدا کردن شماره و ایمیل و لینک توی پیام ها قضیه برعکس شد. جدول زیر چند تا از پیام هایی رو نشون میده که regex نتونست. عدد های ستون Jev احتمال «بله» هستن :
| پیام | سوال | regex رایج | regex با پیشپردازش | Jev |
|---|---|---|---|---|
| صفر نهصد و دوازده، صد و بیست و سه، چهل و پنج، شصت و هفت شماره منه | شماره داره؟ | ✘ | ✘ | ۰.۶۷ ✔ |
| 0912 123 4567 واتساپ دارم | شماره داره؟ | ✘ | ✔ | ۰.۹۲ ✔ |
| کد پیگیری پرداختم 60379912345678 هست ولی سفارشم نیومد | شماره داره؟ | ✘ | ✔ | ۰.۰۴ ✔ |
| ali.rezaei ات جیمیل دات کام | ایمیل داره؟ | ✘ | ✘ | ۰.۹۸ ✔ |
| ali.rezaei [at] gmail [dot] com | ایمیل داره؟ | ✘ | ✔ | ۰.۹۹ ✔ |
| سایت کتابیار دات کام رو سرچ کن | لینک داره؟ | ✘ | ✘ | ۰.۹۵ ✔ |
| sitename[.]ir | لینک داره؟ | ✘ | ✔ | ۰.۹۷ ✔ |
یعنی اگه کاربر شمارهش رو با حروف بنویسه یا به جای نقطه بنویسه «دات»، regex هیچ جوره نمیبینه ولی Jev میبینه. البته همه این پیام ها رو خودم نوشتم و ۴۴ تا پیام هم عدد بزرگی نیست. پس ۱۰۰ درصد اینجا به این معنی نیست که روی پیام های واقعی هم همینقدر خوبه.
راستی کل این آزمایش با ۲,۲۴۷ تا درخواست و ۲۲,۰۶۱ تا سوال، ۷ سنت خرج برداشت.
خلاصه اینکه اگه میخواید چک کنید یه ایمیل یا شماره درست وارد شده یا نه، همون regex (با چند خط کد) رو نگه دارید. هم میلیون ها بار سریعتره، هم تقریبا مجانیه، هم دقیقتره. ولی اگه میخواید بفهمید کسی تو پیامش شماره یا لینک قایم کرده یا نه، Jev میارزه 🙂
آپدیت دوشنبه، ۳۰ شهریور ۱۴۰۵ :
یه مدل دیگه هم هست به اسم Laya از شرکت Convai Innovations که دقیقا همون کار Jev رو میکنه. همون شکل سوال ها (بله/خیر، چند گزینهای و نمره) و همون جواب عددی بین ۰ تا ۱. فرقش اینه که متنبازه و میشه روی کامپیوتر خودتون اجراش کنید. یعنی بعد از اینکه دانلودش کردید نه اینترنت میخواد نه پول 🙂 توی صفحهش هم ادعا کرده ۶ تا ۸ برابر از Jev سریعتره و روی چند تا بنچمارک هم دقیقتره.
گفتم خب اینم بذارم کنار بقیه! سه تا نسخه داره : نسخه انگلیسی، نسخه چندزبانه و یه نسخه که روی چند تا کار مشخص (مثل پشتیبانی مشتری و بررسی فاکتور) آموزش دیده. من دو تای اول رو تست کردم. یه ابزار کوچیک هم کنارش داده که خودش تشخیص میده متن انگلیسیه یا نه و میفرستش سمت نسخه مناسب. من همون ۶۶۶ تا نمونه رو با همون سوال های انگلیسی که به Jev داده بودم، تک به تک بهش دادم. پس باید با ستون «Jev با متن ساده» مقایسهش کرد :
| Jev با متن ساده | Laya | |
|---|---|---|
| چک کردن درستی ایمیل، تاریخ و … (۵۳۴ تا) | ۷۷.۹ | ۵۰.۶ |
| پیدا کردن شماره، ایمیل و لینک توی پیام (۱۳۲ تا) | ۱۰۰ | ۳۰.۳ |
یعنی چی؟ یعنی توی چک کردن درستی عملا شیر یا خط انداخت. توی پیام ها هم از شیر یا خط بدتر شد! چرا؟ چون تقریبا به هر سوالی گفت «بله». از اون ۱۳۲ تا سوال فقط جواب ۳۱ تاش «بله» بود ولی Laya به ۱۱۷ تاش گفت «بله». جدول زیر چند تا نمونه رو نشون میده. عدد ها احتمال «بله» هستن :
| متن | سوال | جواب درست | Jev | Laya |
|---|---|---|---|---|
| [email protected] | ایمیل درسته؟ | آره | ۰.۹۴ | ۰.۱۰ |
| 9:05 | ساعت به شکل HH:MM هست؟ | نه | ۰.۹۳ | ۰.۳۶ |
| 0912 123 4567 واتساپ دارم | ایمیل داره؟ | نه | ۰.۰۱ | ۱.۰۰ |
| صفر نهصد و دوازده، صد و بیست و سه، چهل و پنج، شصت و هفت شماره منه | لینک داره؟ | نه | ۰.۰۱ | ۱.۰۰ |
| ali.rezaei ات جیمیل دات کام | شماره داره؟ | نه | ۰.۰۲ | ۱.۰۰ |
| ali.rezaei [at] gmail [dot] com | ایمیل داره؟ | آره | ۰.۹۹ | ۰.۳۰ |
همونطور که میبینید یه جا که Jev سوتی داده بود رو درست گفت، ولی یه ایمیل کاملا سالم رو رد کرد و به پیامی که فقط شماره موبایل توشه با اطمینان کامل گفت ایمیل داره :/
اول باید مطمئن میشدم که مشکل از تنظیمات من نیست. برای همین مثال خود صفحهش رو اجرا کردم (یه ایمیل که مشتری میگه دو بار ازش پول کم شده و باید بگه مال کدوم بخشه) و درست جواب داد. بعد ۸ تا تیتر خبری ساده بهش دادم، ۴ تا انگلیسی و ۴ تا فارسی، که بگه ورزشیه یا اقتصادی یا فناوری یا بینالملل. هر ۸ تا رو درست گفت. پس مدل سالمه و موضوع کلی یه متن رو میفهمه، ولی وقتی پای یه قانون دقیق وسط میاد (مثل همین آزمون ها) کم میاره.
نکته جالبش اینه که خود صفحهش هم یه جا صادقانه نوشته که نسخه پایه، بدون اینکه روی داده خودتون آموزش ببینه، نزدیک شیر یا خط جواب میده. اون دقت بالایی که اعلام کرده مال نسخهایه که روی همون بنچمارک آموزش دیده. عدد های Jev توی جدول مقایسهشون رو هم خودشون اندازه نگرفتن و از جای دیگه آوردن.
اینجا دیگه Laya برندهست. هر سوال روی کارت گرافیک (RTX 3090) حدود ۲۱ میلیثانیه طول کشید و روی CPU (Ryzen 9 7900X) حدود ۲۲۰ میلیثانیه. اگه همون حساب ۱ میلیون تا رو بکنیم :
| زمان برای ۱ میلیون | هزینه برای ۱ میلیون | |
|---|---|---|
| regex (روی یه هسته CPU) | ۰.۱۸ ثانیه | تقریبا صفر |
| Jev تک به تک، یکی بعد از دیگری | ۸ روز | ۱۶.۶ دلار |
| Laya تک به تک روی کارت گرافیک | ۶ ساعت | مجانی |
| Laya تک به تک روی CPU | ۲.۵ روز | مجانی |
البته Jev رو از ایران و با پروکسی صدا میزدم و حدود ۰.۵ ثانیهش فقط رفت و برگشت اینترنت بود، پس بیشتر این فرق مال شبکهست. ولی خب سرعت به چه دردی میخوره وقتی جواب درست نیست؟ 🙂
خلاصه اینکه Laya سریعه و مجانیه، ولی بدون اینکه روی داده خودتون آموزشش بدید، حداقل برای این کار ها به درد نمیخوره. پس حرف اول پست هنوز سر جاشه : برای چک کردن درستی ایمیل و شماره همون regex با چند خط کد، برای پیدا کردن شماره و لینکی که توی پیام قایم شده Jev 🙂
اینم regex هایی که توی آزمون استفاده کردم. همشون با ماژول re پایتون و تنظیمات پیشفرضش اجرا شدن. فقط UUID رو با re.I اجرا کردم که حروف بزرگ و کوچیک فرقی نکنن. برای چک کردن درستی از re.match استفاده کردم و همه الگو ها با ^ شروع و با $ تموم میشن. یعنی کل متن باید با الگو جور باشه :
validate = { "email": r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', "url": r'^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$', "ipv4": r'^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$', "mobile": r'^(\+98|0098|98|0)?9\d{9}$', "nid": r'^\d{10}$', "iso_date": r'^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$', "jalali": r'^1[34]\d{2}/(0?[1-9]|1[0-2])/(0?[1-9]|[12]\d|3[01])$', "hex": r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$', "uuid": r'^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', # re.I "time": r'^([01]\d|2[0-3]):([0-5]\d)$', "password": r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$', "persian": r'^[\u0600-\u06FF\s]+$', }
جدول زیر نشون میده هر کدوم چی رو چک میکنه، از نمونه هاش چند تا رو درست جواب داد و کجا اشتباه کرد :
| چی رو چک میکنه؟ | درست جواب داد | کجا اشتباه کرد؟ |
|---|---|---|
| ایمیل | ۳۱ از ۴۶ | نقطه اول یا آخر اسم، دو تا نقطه پشت هم، خط تیره اول دامنه، Enter آخر متن |
| آدرس سایت | ۳۴ از ۴۶ | دو تا نقطه پشت هم، _ توی دامنه، خط تیره اول دامنه، پورت بزرگتر از ۶۵۵۳۵ |
| IP | ۴۴ از ۴۶ | Enter آخر متن، ارقام فارسی |
| شماره موبایل | ۴۳ از ۴۶ | ارقام فارسی، Enter آخر متن |
| کد ملی | ۲۶ از ۴۰ | رقم کنترل رو چک نمیکنه، ۱۰ تا رقم یکسان (مثل 1111111111)، ارقام فارسی، Enter آخر متن |
| تاریخ میلادی | ۳۸ از ۴۶ | روز هایی که وجود ندارن، مثل ۳۰ فوریه یا ۳۱ آوریل |
| تاریخ شمسی | ۳۸ از ۴۶ | روز ۳۱ برای مهر تا اسفند، ۳۰ اسفند توی سال غیر کبیسه |
| کد رنگ | ۴۳ از ۴۴ | Enter آخر متن |
| UUID | ۴۱ از ۴۲ | Enter آخر متن |
| ساعت (HH:MM) | ۴۳ از ۴۴ | Enter آخر متن |
| رمز عبور قوی | ۴۱ از ۴۴ | ارقام فارسی، Enter آخر متن |
| متن فقط فارسی | ۳۲ از ۴۴ | هر متنی که نیمفاصله داشت |
برای پیدا کردن توی پیام هم از re.search استفاده کردم، یعنی کافیه یه جای پیام با الگو جور باشه. الگو ها هم تقریبا همونان، فقط ^ و $ ندارن :
detect = { "mobile": r'(?:\+98|0098|0)?9\d{9}', "email": r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', "link": r'https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)', }
اینم نسخه «با پیشپردازش». اول پیام از یکی از این سه تا تابع رد میشه و بعد regex روش اجرا میشه. تابع ها و regex های این بخش رو خودم برای همین آزمون نوشتم :
def normalize_phone(s): s = s.translate(str.maketrans('۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩', '01234567890123456789')) return re.sub(r'(?<=\d)[\s\-.\u200c()]+(?=\d)', '', s) def normalize_email(s): s = re.sub(r'\s*[\[({]\s*at\s*[\])}]\s*|\s+at\s+', '@', s, flags=re.I) return re.sub(r'\s*[\[({]\s*dot\s*[\])}]\s*|\s+dot\s+', '.', s, flags=re.I) def normalize_link(s): s = normalize_email(s) return re.sub(r'\s*[\[({]\s*(?:dot|\.)\s*[\])}]\s*|\s+dot\s+', '.', s, flags=re.I) detect_norm = { "mobile": (normalize_phone, r'(?<!\d)(?:\+98|0098|0)?9[0-9]{9}(?!\d)'), "email": (normalize_email, r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'), "link": (normalize_link, r'(?i)(?:https?://|www\.)\S+|(?<![@\w.])[a-z0-9-]+(?:\.[a-z0-9-]+)*\.(?:com|ir|net|org|me|io|ly|al|co|app|info|xyz)\b(?:/\S*)?'), }
دو تا نکته ریز داره. توی موبایل، (?<!\d) و (?!\d) یعنی درست قبل و بعد شماره نباید رقم دیگهای باشه. همین باعث شد دیگه وسط کد پیگیری ۱۴ رقمی شماره پیدا نکنه. لینک رو هم اینجوری عوض کردم که لینک بدون http:// رو هم پیدا کنه، ولی فقط اگه آخرش یکی از پسوند های این لیست باشه (مثل .com و .ir). جدول زیر نشون میده هر کدوم از ۴۴ تا پیام، چند تا رو درست گفتن :
| regex رایج | regex با پیشپردازش | |
|---|---|---|
| شماره موبایل | ۳۲ از ۴۴ | ۴۲ از ۴۴ |
| ایمیل | ۴۰ از ۴۴ | ۴۳ از ۴۴ |
| لینک | ۳۷ از ۴۴ | ۴۳ از ۴۴ |
اون ۴ تایی هم که با پیشپردازش باز درست نشد، همونایی بودن که شماره یا ایمیل یا لینک رو با حروف نوشته بودن. مثل «صفر نهصد و دوازده...» یا «ات جیمیل دات کام». اینا رو دیگه regex به این سادگی نمیبینه 🙂
nb.neighbours()
| title | date | |
|---|---|---|
| prev | یک چالش وباسکرپینگ که خودش خودش را میشکند | ۱۴۰۵/۰۵ |
| next | بلندگوی مدرسه تا کجا صداش میاد؟! | ۱۴۰۵/۰۷ |