سلام! من سارا بحرانیام و خیلی خوشحالم که اینجایی. تا حالا شده بخوای یک کلمهی خاص رو توی متن پیدا کنی، اما نتایج جستجوت پر از کلمات ناخواستهی دیگه باشه؟ مثلاً دنبال “cat” میگردی ولی “caterpillar” هم پیدا میشه؟ اینجاست که یکی از قدرتمندترین ابزارهای Regex به کمکت میاد: b یا «مرز کلمه».
درک این مفهوم یکی از پایههای اساسی درک انکرها و موقعیت یابی در رجکس (Anchor & Positioning in Regex) است. خیلیها b رو با فاصله (Space) اشتباه میگیرن و همین باعث میشه در تحلیل دادههای سرچ کنسول یا نوشتن کدهای پایتون به مشکل بخورن.
در این راهنمای جامع، میخوام بهت یاد بدم b دقیقاً چیه، چطور کار میکنه، چطور در زبان فارسی ازش استفاده کنی و کی باید سراغ برادر مخالفش، B، بری. آمادهای که جستجوهات رو میلیمتری دقیق کنی؟
جدول کاربردی: مقایسه سریع مفاهیم کلیدی مرزبندی
قبل از اینکه عمیق بشیم، این جدول خلاصه به تو کمک میکنه تفاوتهای اصلی این مفاهیم رو در یک نگاه ببینی:
| متاکاراکتر | نام کامل (فارسی) | کاری که انجام میدهد | مثال در متن “The cat!” |
|---|---|---|---|
| b | مرز کلمه (Word Boundary) | موقعیتی بین یک کاراکتر کلمه (w) و غیر-کلمه (W) را پیدا میکند. | قبل از ‘c’ و بعد از ‘t’ |
| B | نبود مرز کلمه (Non-Word Boundary) | موقعیتی که مرز کلمه نیست (یعنی بین دو w یا دو W). | بین ‘c’ و ‘a’ و بین ‘a’ و ‘t’ |
| w | کاراکتر کلمه (Word Character) | خودِ کاراکتر (حروف، اعداد، آندرلاین) را تطبیق میدهد. | ‘c’, ‘a’, ‘t’ |
| W | کاراکتر غیر-کلمه (Non-Word Character) | خودِ کاراکتر (فاصله، نقطه، علامت تعجب) را تطبیق میدهد. | ‘ ‘ (فاصله), ‘!’ |
b چیست؟ تعریف دقیق مفهوم «مرز کلمه»
اگه بخوام خیلی ساده و مستقیم بهت بگم، b یکی از متاکاراکترهای قدرتمند در عبارات باقاعده (Regex) هست که مخفف «مرز کلمه» (Word Boundary) است.
کاربرد اصلی و حیاتی b اینه که به تو اجازه میده کلمات کامل رو جستجو کنی.
فرض کن میخوای کلمهی “cat” رو در یک متن پیدا کنی. اگه فقط “cat” رو جستجو کنی، ممکنه نتایج ناخواستهای مثل “education” یا “catch” هم برات پیدا بشن. اینجاست که b به کمکت میاد.
وقتی تو از الگوی bcatb استفاده میکنی، به موتور Regex دستور میدی: “من فقط و فقط خودِ کلمهی ‘cat’ رو میخوام؛ نه کلماتی که ‘cat’ بخشی از اونهاست.”
اما نکتهی کلیدی و کمی فریبنده اینجاست: b خودش هیچ کاراکتری (مثل فاصله، نقطه یا ویرگول) رو انتخاب یا تطبیق نمیده. بلکه فقط یک موقعیت یا نقطه خاص رو در متن پیدا میکنه. در بخشهای بعدی دقیقاً بهت میگم این «موقعیت» یعنی چی.
b به عنوان یک «لنگر صفر-پهنا» (Zero-Width Anchor)
این مهمترین نکتهایه که باید در مورد b بدونی و تفاوتش رو با بقیهی کاراکترها مشخص میکنه. در دنیای Regex، به b میگن یک «لنگر صفر-پهنا» (Zero-Width Anchor).
بذار این اصطلاح فنی رو برات به زبان ساده باز کنم:
«صفر-پهنا» (Zero-Width): این یعنی b هیچ فضایی از متن رو اشغال نمیکنه. برخلاف کاراکتر فاصله (space) که خودش یک کاراکتر حساب میشه و “پهنا” داره، b فقط یک موقعیت رو چک میکنه و هیچ کاراکتری رو “مصرف” نمیکنه.
«لنگر» (Anchor): این یعنی b مثل لنگر کشتی، یک ادعا رو در مورد یک موقعیت خاص در متن مطرح میکنه. کارش این نیست که کاراکتری رو پیدا کنه، کارش اینه که بگه “هی! دقیقاً همینجا که من هستم، مرز یک کلمه وجود داره.”
متاکاراکترهای دیگهای مثل ^ (لنگر شروع خط) و $ (لنگر پایان خط) هم دقیقاً همینطور «لنگر صفر-پهنا» هستن. اونها هم کاراکتری رو انتخاب نمیکنن، بلکه فقط یک موقعیت خاص (شروع یا پایان متن) رو نشان میدن.
تفاوت کلیدی b با w (کاراکتر کلمه): تطبیق موقعیت به جای کاراکتر
اینجا دقیقاً همونجاییه که خیلی از افراد تازهکار گیج میشن. درک تفاوت این دو، کلید فهمیدن b است.
w (کاراکتر کلمه): این متاکاراکتر یک کاراکتر رو تطبیق میده. کارش اینه که بگرده و یک حرف الفبا (a-z, A-Z)، یک عدد (0-9) یا کاراکتر آندرلاین (_) رو پیدا کنه و انتخابش کنه.
b (مرز کلمه): این متاکاراکتر هیچ کاراکتری رو تطبیق نمیده. فقط یک موقعیت (Position) بین دو کاراکتر رو بررسی میکنه و اگه اون موقعیت، «مرز کلمه» بود، اون موقعیت رو نشان میده.
بیا یه مثال خیلی واضح بزنیم:
فرض کن عبارت “OK!” رو داریم.
اگه در این عبارت دنبال w بگردی، موتور Regex دو نتیجه برات پیدا میکنه: کاراکتر ‘O’ و کاراکتر ‘K’.
اگه دنبال b بگردی، موتور Regex دو موقعیت رو برات پیدا میکنه:
موقعیت قبل از ‘O‘: (چون قبلش هیچی نیست و ‘O’ یک کاراکتر کلمه است).
موقعیت بعد از ‘K‘: (چون ‘K’ یک کاراکتر کلمه است، اما ‘!’ یک کاراکتر کلمه نیست).
نکته کلیدی: w خودِ “آجر” (کاراکتر) رو برمیداره، ولی b “ملات” یا “فاصله” نامرئی بین آجرها (یا بین آجر و هوا) رو پیدا میکنه.
b چگونه کار میکند؟ آشنایی با w و W
حالا که فرق «موقعیت» و «کاراکتر» رو فهمیدی، وقتشه ببینیم موتور Regex چطوری اون «موقعیت» مرزی رو تشخیص میده.
موتور Regex برای پیدا کردن b، همیشه به کاراکتر قبل و بعد اون موقعیت نگاه میکنه. برای این کار، همهی کاراکترها رو به دو دسته تقسیم میکنه:
w (Word Character): کاراکترهای کلمه. شامل: حروف a-z, A-Z، اعداد 0-9، و آندرلاین _.
W (Non-Word Character): کاراکترهای غیر-کلمه. یعنی دقیقاً هر چیزی که w نیست. مثل: فاصله (space)، نقطه، ویرگول، علامت تعجب (!)، ستاره (*)، و حتی رفتن به خط بعد.
یک موقعیت، b (مرز کلمه) محسوب میشه، اگر و تنها اگر:
در یک سمتش کاراکتر w (کلمه) باشه و در سمت دیگرش کاراکتر W (غیر-کلمه).
این حالت معمولاً در دو جا اتفاق میفته:
ابتدای کلمه: کاراکتر قبلی W (مثلاً فاصله) و کاراکتر بعدی w (مثلاً حرف ‘S’) باشه.
انتهای کلمه: کاراکتر قبلی w (مثلاً حرف ‘O’) و کاراکتر بعدی W (مثلاً علامت ‘!’) باشه.
همچنین، شروع و پایان کل متن هم به عنوان «هیچی» یا «مرز» در نظر گرفته میشن. پس اگه کلمهای در اول یا آخر متن باشه هم، b تطبیق داده میشه.
مثال نهایی برای جمعبندی:
در عبارت “Come on, SEO!” ما این مرزها (b) رو داریم:
bCome (قبل از C، چون شروع متنه)
Comeb (بعد از e، چون بعدش فاصله W اومده)
bon (قبل از o، چون قبلش فاصله W بوده)
onb (بعد از n، چون بعدش ویرگول W اومده)
bSEO (قبل از S، چون قبلش فاصله W بوده)
SEOb (بعد از O، چون بعدش علامت ! اومده)
(توجه: بین ! و پایان متن b نداریم، چون هیچکدوم w نیستن)
با درک این مفهوم، تو حالا میتونی در ابزارهایی مثل گوگل آنالیتیکس یا سرچ کنسول، جستجوهای Regex خیلی دقیقتری انجام بدی و مثلاً با الگوی bseob، مطمئن بشی که فقط دادههای مربوط به خودِ کلمهی “SEO” رو میبینی، نه کلماتی مثل “seobility” یا “seoblog”.
مکانیک داخلی b: موتور Regex «مرز» را چگونه تشخیص میدهد؟
خب، همونطور که گفتم، b یک «لنگر صفر-پهنا» (Zero-Width Anchor) است. این یعنی b خودش هیچ کاراکتری رو اشغال نمیکنه، بلکه فقط یک موقعیت (Position) رو بررسی میکنه.
موتور Regex برای اینکه تشخیص بده آیا یک موقعیت خاص، «مرز کلمه» هست یا نه، یک کار خیلی ساده انجام میده:
به کاراکتر درست قبل از اون موقعیت و کاراکتر درست بعد از اون موقعیت نگاه میکنه.
برای این بررسی، موتور Regex همهی کاراکترهای دنیا رو فقط به دو دسته میشناسه:
w (Word Character): کاراکترهای کلمه (حروف الفبا، اعداد، آندرلاین).
W (Non-Word Character): کاراکترهای غیر-کلمه (فاصله، نقطه، ویرگول، علامت تعجب، و …).
قانون طلایی: یک موقعیت، b (مرز کلمه) است، اگر و تنها اگر، یکی از این دو حالت برقرار باشه:
یک سمتش w باشه و سمت دیگهاش W.
یک سمتش w باشه و سمت دیگهاش «هیچی» باشه (یعنی اول یا آخر متن).
همین! موتور Regex فقط همین عدم تطابق بین دو طرف یک موقعیت رو چک میکنه. حالا بیا سناریوهایی که گفتی رو دقیق بررسی کنیم.
سناریو ۱: تطبیق در ابتدای یک رشته (قبل از یک کاراکتر کلمه)
این سناریو خیلی رایجه. فرض کن رشتهی ما “SEO” هست و ما میخوایم bSEO رو پیدا کنیم.
موتور Regex به اولین موقعیت ممکن، یعنی قبل از کاراکتر ‘S’ میره.
بررسی کاراکتر قبلی: به عقب نگاه میکنه. هیچی وجود نداره (شروع رشته).
بررسی کاراکتر بعدی: به جلو نگاه میکنه. کاراکتر ‘S’ رو میبینه. ‘S’ جزو دستهی w (کاراکتر کلمه) است.
تصمیمگیری: موتور Regex، «هیچی» (شروع رشته) رو معادل W (غیر-کلمه) در نظر میگیره. پس وضعیت اینه: (سمت قبل: W) و (سمت بعد: w).
نتیجه: چون این دو دسته با هم فرق دارن، موتور میگه: “آها! اینجا یک مرز کلمه (b) است.” و تطبیق با موفقیت انجام میشه.
سناریو ۲: تطبیق در انتهای یک رشته (بعد از یک کاراکتر کلمه)
این هم دقیقاً مثل سناریوی قبلی، ولی برعکسه. فرض کن رشتهی ما همون “SEO” هست و ما دنبال SEOb میگردیم.
موتور Regex به آخرین موقعیت ممکن، یعنی بعد از کاراکتر ‘O’ میره.
بررسی کاراکتر قبلی: به عقب نگاه میکنه. کاراکتر ‘O’ رو میبینه. ‘O’ جزو دستهی w (کاراکتر کلمه) است.
بررسی کاراکتر بعدی: به جلو نگاه میکنه. هیچی وجود نداره (پایان رشته).
تصمیمگیری: موتور Regex، «هیچی» (پایان رشته) رو هم معادل W (غیر-کلمه) در نظر میگیره. پس وضعیت اینه: (سمت قبل: w) و (سمت بعد: W).
نتیجه: باز هم چون این دو دسته با هم فرق دارن، موتور میگه: “اینجا هم یک مرز کلمه (b) است.” و تطبیق با موفقیت انجام میشه.
سناریو ۳: تطبیق بین یک کاراکتر کلمه (w) و یک کاراکتر غیر-کلمه (W)
این رایجترین حالتیه که وسط متن اتفاق میفته و قدرت واقعی b رو نشون میده. بیا دو حالت رو در رشتهی “Go SEO!” بررسی کنیم:
حالت اول: پایان کلمهی “Go” (بین ‘o’ و فاصله)
موتور Regex موقعیت بین ‘o’ و ‘ ‘ (فاصله) رو بررسی میکنه.
بررسی کاراکتر قبلی: ‘o’ (که یک w است).
بررسی کاراکتر بعدی: ‘ ‘ (فاصله، که یک W است).
نتیجه: چون w و W متفاوت هستن، پس اینجا b تطبیق داده میشه.
حالت دوم: شروع کلمهی “SEO” (بین فاصله و ‘S’)
موتور Regex موقعیت بین ‘ ‘ (فاصله) و ‘S’ رو بررسی میکنه.
بررسی کاراکتر قبلی: ‘ ‘ (فاصله، که یک W است).
بررسی کاراکتر بعدی: ‘S’ (که یک w است).
نتیجه: باز هم چون W و w متفاوت هستن، اینجا هم b تطبیق داده میشه.
حالا یک سوال مهم: چرا بین ‘E’ و ‘O’ در “SEO” مرز کلمه نیست؟
چون وقتی موتور Regex موقعیت بین ‘E’ و ‘O’ رو بررسی میکنه:
کاراکتر قبلی: ‘E’ (که w است).
کاراکتر بعدی: ‘O’ (که w است).
نتیجه: چون هر دو طرف از یک دسته (w) هستن، موتور میگه: “اینجا مرز نیست، اینجا وسط کلمه است.”
درک این مکانیک ساده به تو کمک میکنه که در تحلیل دادههای سرچ کنسول یا آنالیتیکس، با استفاده از الگوی b(keyword)b، دقیقاً خودِ کلمه کلیدی مورد نظرت رو فیلتر کنی و نویزها رو حذف کنی.
کاربردهای عملی و مثالهای واقعی استفاده از b
شاید فکر کنی b فقط به درد برنامهنویسهای حرفهای میخوره، اما واقعیت اینه که هرکسی که با متن کار میکنه (مثل یک کارشناس سئو، محتوانویس، یا تحلیلگر داده) میتونه ازش برای دقیقتر کردن کارها و صرفهجویی کلی در زمان استفاده کنه. b یعنی خداحافظی با نتایج جستجوی ناخواسته!
مثال کلاسیک: جستجوی یک کلمه کامل (Whole Word Search)
این اصلیترین و رایجترین کاربرد b هست.
درواقع، اون گزینهای که تو در نرمافزارهایی مثل Microsoft Word، Google Docs یا ویرایشگرهای کد به اسم “Match whole word only” یا “جستجوی کلمهی کامل“ میبینی، دقیقاً داره در پشت صحنه از همین b استفاده میکنه.
فرض کن تو مسئول تحلیل دادههای سرچ کنسول هستی و میخوای ببینی کوئریهایی که دقیقاً شامل کلمهی “خرید” بودن، چقدر ورودی داشتن.
جستجوی عادی (بدون b): اگه فقط “خرید” رو فیلتر کنی، کوئریهایی مثل “خریدار”، “خریداری” یا “بهترینخرید” هم در نتایجت ظاهر میشن و تحلیلت رو خراب میکنن.
جستجوی دقیق (با b): اما اگه در بخش Regex سرچ کنسول از الگوی bخریدb استفاده کنی، به گوگل میگی: “فقط و فقط خودِ کلمهی ‘خرید’ رو برام بیار.” اینطوری “خرید مبل” میاد، اما “خریدار مبل” فیلتر میشه.
تفاوت حیاتی جستجوی “cat” با bcatb
بیا این تفاوت رو با همون مثال معروف “cat” ببینیم تا اهمیتش کامل برات جا بیفته.
فرض کن این متن رو داریم:
“The cat quickly caught a caterpillar. It was very educated.”
حالا میخوایم کلمهی “cat” رو در این متن پیدا کنیم:
| الگوی جستجو (Pattern) | نتایج پیدا شده در متن | توضیح |
|---|---|---|
| cat (بدون مرز) | cat (در The cat)، caterpillar، educated | موتور Regex هر توالی “c-a-t” رو که پشت سر هم ببینه، انتخاب میکنه. براش مهم نیست که این حروف بخشی از کلمهی بزرگتری هستن یا نه. |
| bcatb (با مرز) | cat (در The cat) | موتور Regex فقط دنبال کلمهی کامل “cat” میگرده؛ یعنی کلمهای که در دو طرفش “مرز کلمه” (در اینجا، فاصله) وجود داره. به همین دلیل “caterpillar” و “educated” رو هوشمندانه نادیده میگیره. |
این تفاوت برای ما که با هزاران کلمه کلیدی طولانی و کوتاه سروکار داریم، حیاتیه و مرز بین یک تحلیل دقیق و یک تحلیل پر از نویز رو مشخص میکنه.
استفاده از b برای جایگزینی (Replace) دقیق کلمات در متن
قدرت b فقط در پیدا کردن (Find) نیست، بلکه در جایگزین کردن (Replace) هم معجزه میکنه.
سناریو: تصور کن تو یک مقالهی ۵۰۰۰ کلمهای در مورد سئو نوشتی و ۱۰۰ بار از کلمهی “لینک” استفاده کردی. حالا طبق استراتژی محتوایی جدید، تصمیم گرفتی تمام کلمات “لینک” رو به “پیوند داخلی” تغییر بدی.
چالش (جایگزینی عادی): اگه از Find & Replace ساده استفاده کنی (Ctrl+H) و “لینک” رو با “پیوند داخلی” عوض کنی، یک فاجعه رخ میده! کلمهای مثل “لینکدین” (LinkedIn) تبدیل میشه به “پیوند داخلیدین” و کلمهی “لینکسازی” میشه “پیوند داخلیسازی”.
راهحل (جایگزینی با b):
در ویرایشگر خودت (مثل VS Code یا حتی Google Docs)، گزینهی “Use regular expressions” (استفاده از عبارات باقاعده) رو فعال میکنی.
در فیلد “Find” وارد میکنی: bلینکb
در فیلد “Replace” وارد میکنی: پیوند داخلی
نتیجه: موتور Regex فقط و فقط کلمهی کامل “لینک” رو پیدا میکنه و با “پیوند داخلی” جایگزین میکنه و به کلماتی مثل “لینکدین” یا “لینکسازی” اصلاً دست نمیزنه.
اعتبارسنجی ورودیها: اطمینان از شروع یا پایان ورودی با یک کلمه
این کاربرد کمی فنیتره و بیشتر در برنامهنویسی یا اعتبارسنجی فرمها (Form Validation) استفاده میشه، اما دونستنش دید خیلی خوبی بهت میده.
سناریو: فرض کن تو یک فیلد در فرم سایتت داری که کاربر باید “نام کاربری” یا “تگ” (Tag) وارد کنه. تو میخوای مطمئن بشی که ورودی کاربر فقط یک کلمهی واحد (شامل حروف، اعداد یا آندرلاین) هست و هیچ فاصله، علامت تعجب یا کاراکتر خاص دیگهای نداره.
چالش: کاربر ممکنه وارد کنه: “my tag” (با فاصله) یا “!seo” (با علامت).
راهحل (استفاده از Regex برای اعتبارسنجی):
تو میتونی از این الگو برای چک کردن ورودی استفاده کنی: ^bw+b$
بیا این الگوی قدرتمند رو با هم بشکافیم:
^ (لنگر شروع): به موتور میگه دقیقاً از ابتدای رشته شروع به بررسی کن.
b (مرز کلمه): مطمئن میشه که ورودی با یک مرز شروع میشه (یعنی بلافاصله بعدش قراره یک کاراکتر کلمه w بیاد).
w+ (کاراکتر کلمه): به موتور میگه “یک یا چند” کاراکتر کلمه (حروف a-z، اعداد 0-9، یا آندرلاین _) رو پیدا کن.
b (مرز کلمه): مطمئن میشه که کلمه در اینجا تموم شده (یعنی بعدش یا هیچی نیست یا یک W هست).
$ (لنگر پایان): به موتور میگه دقیقاً باید به انتهای رشته رسیده باشی.
نتیجه:
ورودی “Seo_Expert_1” قبول میشه (چون همهاش w هست و در دو طرفش مرز قرار داره).
ورودی “seo expert” رد میشه (به خاطر وجود فاصله W در وسط).
ورودی “!seo” رد میشه (چون با W شروع شده و الگوی ^bw+ تطبیق پیدا نمیکنه).
مقایسه b (مرز کلمه) با B (نبود مرز کلمه)
اگه بخوام خیلی خلاصه بگم: Bدقیقاً، صددرصد و کاملاً نقطهی مقابل bاست.
یادته گفتیم b یک موقعیته که یک طرفش کاراکتر کلمه (w) و طرف دیگهاش کاراکتر غیر-کلمه (W) است؟ خب، B دقیقاً جاییه که اینطور نیست.
b (مرز کلمه): دنبال لبهی کلمه میگرده. جایی که کلمه به غیر-کلمه میرسه (یا برعکس).
B (نبود مرز کلمه): دنبال جایی میگرده که لبه نیست. یعنی وسط یک کلمه، یا وسط یک رشته از کاراکترهای غیر-کلمه.
این جدول مقایسه رو ببین تا تفاوتشون کامل برات جا بیفته:
| ویژگی | b (مرز کلمه) | B (نبود مرز کلمه) |
|---|---|---|
| تعریف | یک موقعیت بین w و W | یک موقعیت بین w و w یا بین W و W |
| چیزی که پیدا میکنه | لبهها (شروع و پایان کلمات) | هرجایی به جز لبهها (وسط کلمات، وسط علائم) |
| مثال در “cat!” | قبل از ‘c’ و بعد از ‘t’ | بین ‘c’ و ‘a’، و بین ‘a’ و ‘t’ |
B دقیقاً چه چیزی را پیدا میکند؟
B (مخفف Non-Word Boundary یا نبود مرز کلمه) هم یک «لنگر صفر-پهنا» است. یعنی کاراکتری رو انتخاب نمیکنه، فقط یک موقعیت رو بررسی میکنه.
B یک موقعیت رو تطبیق میده، اگر و تنها اگر هر دو طرف اون موقعیت از یک جنس باشن.
این یعنی دو سناریوی اصلی:
موقعیت بین دو کاراکتر کلمه (هر دو w):
این دقیقاً یعنی “وسط یک کلمه”.
در کلمهی “Regex”، موقعیت بین ‘R’ و ‘e’، بین ‘e’ و ‘g’، بین ‘g’ و ‘e’، و بین ‘e’ و ‘x’ همگی B هستن. چون هر دو طرفشون کاراکتر کلمه (w) است.
موقعیت بین دو کاراکتر غیر-کلمه (هر دو W):
این یعنی “وسط یک رشته از علائم یا فاصلهها”.
در عبارت “…SEO…”، موقعیت بین دو نقطهی اول (.) و همچنین بین دو نقطهی دوم، B محسوب میشه. چرا؟ چون هر دو طرف اون موقعیت، کاراکتر غیر-کلمه (W) هستن.
پس به زبان ساده، B به موتور Regex میگه: “من جایی رو میخوام که وسط یه تیکه متن یکپارچه باشه؛ یا وسط حروف و اعداد، یا وسط علائم و فاصلهها.”
مثال عملی: چه زمانی باید از B استفاده کنیم؟ (مثلاً پیدا کردن کلمه در داخل کلمهای دیگر)
این دقیقاً کاربرد اصلی B هست. استفاده از B خیلی کمتر از b رایجه، اما برای کارهای خیلی خاص و دقیق، حیاتیه.
فرض کن همون متن معروف رو داریم:
“The cat quickly caught a caterpillar. It was very educated.”
حالا سناریوهای مختلف رو با ترکیب b و B ببین:
سناریو ۱: پیدا کردن کلماتی که با “cat” شروع میشوند ولی خودِ “cat” نیستند
تو دنبال “caterpillar” یا “catch” هستی، ولی خودِ “cat” رو نمیخوای.
الگو: bcatB
تحلیل الگو:
b: اولش مرز کلمه باشه (یعنی با “cat” شروع بشه).
cat: خودِ حروف “c-a-t”.
B: بلافاصله بعد از ‘t’، مرز کلمه نباشه (یعنی کلمه ادامه داشته باشه).
نتایج در متن:
“cat”: رد میشه. (چون بعد از ‘t’ یک b (مرز) وجود داره، نه B).
“caterpillar”: قبول میشه. (چون قبل از ‘c’ مرز b و بعد از ‘t’ نبود مرز B وجود داره).
“educated”: رد میشه. (چون قبل از ‘c’ مرز b وجود نداره).
سناریو ۲: پیدا کردن کلماتی که به “cat” ختم میشوند ولی خودِ “cat” نیستند
تو دنبال کلماتی مثل “bobcat” یا “muscat” هستی.
الگو: Bcatb
تحلیل الگو:
B: قبل از ‘c’، مرز کلمه نباشه (یعنی “cat” از اول کلمه شروع نشده باشه).
cat: خودِ حروف “c-a-t”.
b: بلافاصله بعد از ‘t’، مرز کلمه باشه (یعنی کلمه اینجا تموم بشه).
نتایج در متن:
“cat”: رد میشه. (چون قبل از ‘c’ مرز b هست، نه B).
(اگر “bobcat” در متن بود، پیدا میشد).
سناریو ۳: پیدا کردن “cat” فقط در وسط یک کلمه (کاربرد اصلی سوال تو)
تو دنبال کلمهای مثل “educated” هستی که “cat” نه اولشه و نه آخرش.
الگو: BcatB
تحلیل الگو:
B: قبل از ‘c’ مرز نباشه.
cat: خودِ حروف “c-a-t”.
B: بعد از ‘t’ هم مرز نباشه.
نتایج در متن:
“cat”: رد میشه (هر دو طرفش b هست).
“caterpillar”: رد میشه (قبل از ‘c’ مرز b هست).
“educated”: قبول میشه! (چون قبل از ‘c’ (یعنی بین ‘u’ و ‘c’) مرز B هست و بعد از ‘t’ (یعنی بین ‘t’ و ‘e’) هم مرز B هست).
همونطور که میبینی، با ترکیب هوشمندانهی b و B، تو کنترل کامل و میلیمتری روی پیدا کردن هر رشتهای در هر موقعیتی از متن داری. این برای پاکسازی دادههای سئو یا تحلیل لاگها فوقالعاده قدرتمنده!
پیادهسازی b در زبانهای برنامهنویسی و ابزارها
خبر خوب اینه که b (و همینطور B) جزو استانداردهای جهانی Regex (PCRE – Perl Compatible Regular Expressions) محسوب میشه. این یعنی تقریباً تمام زبانهای برنامهنویسی مدرن و ابزارهای تحلیل متنی که از Regex پشتیبانی میکنن، b رو دقیقاً با همون مفهومی که یاد گرفتیم، میشناسن.
از پایتون و جاوا اسکریپت گرفته تا PHP، جاوا، C# و ابزارهایی مثل گوگل آنالیتیکس، سرچ کنسول، یا ویرایشگرهای کد مثل VS Code، همگی b رو به عنوان «مرز کلمه» درک میکنن.
بیا چند تا از پرکاربردترینها رو با هم ببینیم.
استفاده از b در پایتون (ماژول re)
در پایتون، ماژول استاندارد برای کار با عبارات باقاعده، ماژول re هست. استفاده از b در پایتون فوقالعاده ساده است، اما یک نکتهی کلیدی داره.
نکته کلیدی: استفاده از Raw Strings (رشتههای خام)
همیشه، همیشه و همیشه، وقتی در پایتون الگوی Regex مینویسی، قبل از علامت کوتیشن، یک حرف r بذار (مثلاً r’bcatb’).
چرا؟ چون بکاسلش () در رشتههای عادی پایتون، کاراکتر “فرار” (Escape) محسوب میشه. مثلاً n یعنی «برو به خط بعد». اگرچه خودِ b در رشتههای عادی پایتون هم به معنی “Backspace” هست (که کار ما رو خراب میکنه!)، استفاده از r (Raw String) به پایتون میگه: “این یک رشتهی خام هست، با بکاسلشها کاری نداشته باش و اونها رو عیناً به موتور Regex تحویل بده.”
مثال: فرض کن میخوایم کلمهی “سئو” رو به صورت کامل در یک متن پیدا کنیم.
import re
text = “آموزش سئو مقدماتی با بهترین متخصص سئوکار. #سئو”
pattern = r’bسئوb’ # <– استفاده از r الزامی است!
matches = re.findall(pattern, text)
print(matches)
# خروجی: [‘سئو’]
همونطور که میبینی، re.findall فقط کلمهی اول “سئو” رو پیدا کرد و “سئوکار” (که به کاراکتر دیگه چسبیده) و “#سئو” (که با W شروع شده ولی بعدش مرز نداره) رو هوشمندانه نادیده گرفت.
کاربرد b در جاوا اسکریپت (JavaScript Regex)
در جاوا اسکریپت، کار با Regex حتی از پایتون هم مستقیمتره. تو میتونی الگوهای Regex رو مستقیماً بین دو علامت اسلش (/) بنویسی.
در جاوا اسکریپت، b دقیقاً همون کارکرد استاندارد رو داره و نیازی به پیشوند خاصی مثل r پایتون هم نداره.
مثال: فرض کن میخوایم تمام کلمات “cat” رو در یک متن پیدا کنیم و اونها رو با “dog” جایگزین کنیم، اما نمیخوایم “caterpillar” تغییر کنه.
let text = “The cat quickly caught a caterpillar.”;
let pattern = /bcatb/g; // ‘g’ یعنی global (همه موارد رو پیدا کن)
// استفاده از .replace()
let newText = text.replace(pattern, “dog”);
console.log(newText);
// خروجی: “The dog quickly caught a caterpillar.”
میبینی؟ “caterpillar” دستنخورده باقی موند، چون الگوی ما (bcatb) به درستی فقط کلمهی کامل “cat” رو هدف قرار داد.
تست و خطایابی b در ابزارهایی مانند Regex101
این مهمترین توصیهی من به توئه: هیچوقت، هیچ الگوی Regex رو مستقیماً در کد اصلی (Production) ننویس!
عبارات باقاعده میتونن به شدت فریبنده باشن. چیزی که فکر میکنی درسته، ممکنه یک حالت خاص (Edge Case) رو در نظر نگرفته باشه و کل دادههات رو خراب کنه. b هم با اینکه ساده به نظر میاد، اما مفهوم «صفر-پهنا» بودنش گاهی گیجکننده میشه.
ابزار نجات: Regex101.com
این وبسایت بهترین دوست تو برای کار با Regex خواهد بود. دلایلش:
تست زنده: تو الگوی خودت (مثلاً bcatb) رو در کادر بالا و متن آزمایشیات رو در کادر پایین وارد میکنی. همون لحظه بهت نشون میده که دقیقاً چی تطبیق داده شده.
بخش توضیحات (Explanation): این بخش معرکهست. در سمت راست صفحه، الگوی تو رو قدم به قدم تحلیل میکنه. مثلاً برای bcatb دقیقاً مینویسه:
b: “یک مرز کلمه رو پیدا کن.”
cat: “حروف ‘c-a-t’ رو پیدا کن.”
b: “یک مرز کلمهی دیگه رو پیدا کن.”
انتخاب طعم (Flavor): میتونی مشخص کنی که این الگو قراره در چه محیطی اجرا بشه (مثلاً Python, JavaScript, PCRE). اینطوری مطمئن میشی که الگوت در اون زبان خاص هم دقیقاً همونطور کار میکنه.
چطور ازش برای bاستفاده کنیم؟ بهترین کار اینه که متنهای مختلف رو تست کنی:
“cat” (باید تطبیق بده)
“a cat.” (باید تطبیق بده)
“caterpillar” (نباید تطبیق بده)
“educated” (نباید تطبیق بده)
“bobcat” (نباید تطبیق بده)
با این ابزار، تو میتونی در عرض چند ثانیه الگوت رو بنویسی، تست کنی، از درست بودنش مطمئن بشی و بعد با خیال راحت در کد پایتون، جاوا اسکریپت، یا حتی در فیلتر Regex گوگل آنالیتیکس ازش استفاده کنی.
اشتباهات رایج و مشکلات b (عیبیابی پیشرفته)
b یکی از پرکاربردترین متاکاراکترهاست، اما دقیقاً به همون اندازه هم میتونه فریبنده باشه. اگه b اونطوری که انتظار داری کار نمیکنه، تقریباً مطمئن باش که دلیلش یکی از مواردیه که الان با هم بررسی میکنیم. این بخش عیبیابی پیشرفتهی تو برای b هست.
چرا b گاهی اوقات کار نمیکند؟ (سوءتفاهمهای رایج)
رایجترین سوءتفاهم اینه:
اشتباه رایج: خیلیها فکر میکنن b یعنی «فاصله» (space) یا «نقطه» یا «ویرگول».
واقعیت: b هیچکدوم از اینا نیست. b یک موقعیت «صفر-پهنا» است. اون فقط به دو طرف خودش نگاه میکنه و میبینه آیا جنس کاراکترها متفاوته یا نه. (یعنی یکی w باشه و اون یکی W).
مثال: فرض کن میخوای bcatb رو در متن “bobcat” پیدا کنی.
قبل از ‘c’: موتور Regex به موقعیت بین ‘b’ و ‘c’ نگاه میکنه.
کاراکتر قبلی: ‘b’ (که یک w است).
کاراکتر بعدی: ‘c’ (که اون هم یک w است).
نتیجه: چون هر دو طرف از یک جنس هستن (w و w)، اینجا مرز کلمه نیست. اینجا B (نبود مرز) هست. پس b تطبیق داده نمیشه و الگوی تو شکست میخوره.
پس یادت باشه: b دنبال فاصله یا نقطه نمیگرده؛ دنبال تغییر ناگهانی جنسیت از w به W (یا برعکس) میگرده.
مشکل b با کاراکترهای خاص (مانند -، _ یا .)
اینجا دقیقاً همونجاییه که اون سوءتفاهم بالا کار دستت میده. همهچیز به تعریف w برمیگرده.
یادآوری: w (کاراکتر کلمه) یعنی: [a-zA-Z0-9_]
مشکل با آندرلاین (_):
آندرلاین (_) رسماً و قانوناً جزو w (کاراکتر کلمه) حساب میشه!
سناریو: تو میخوای کلمهی “word” رو در “my_word” پیدا کنی.
الگو: bwordb
نتیجه: پیدا نمیکنه!
چرا؟ چون وقتی موتور Regex میخواد b رو قبل از ‘w’ تطبیق بده، میبینه که کاراکتر قبلی _ (که w است) و کاراکتر بعدی ‘w’ (که اونم w است). اینجا مرز (b) نیست.
رفتار با خط تیره (–):
خط تیره (-) جزو w نیست. خط تیره یک W (کاراکتر غیر-کلمه) محسوب میشه.
سناریو: تو میخوای کلمهی “seo” رو در “seo-friendly” پیدا کنی.
الگو: bseob
نتیجه: پیدا میکنه!
چرا؟ چون وقتی موتور b رو بعد از ‘o’ بررسی میکنه، میبینه کاراکتر قبلی ‘o’ (که w است) و کاراکتر بعدی ‘-‘ (که W است). این تعریف دقیق b هست.
رفتار با نقطه (.):
نقطه هم مثل خط تیره، یک W است.
بنابراین الگوی bcatb به راحتی “cat” رو در جملهی “I see a cat.” پیدا میکنه.
چالش اصلی: b و کاراکترهای یونیکد (Unicode) و زبان فارسی
این مهمترین بخشیه که تو به عنوان یک متخصص محتوای فارسی باید بدونی.
مشکل: در خیلی از موتورهای Regex (مخصوصاً نسخههای قدیمیتر یا تنظیمات پیشفرض)، تعریف w فقط شامل کاراکترهای ASCII یعنی [a-zA-Z0-9_] است.
فاجعه اینجاست: از نظر این موتورها، حروف فارسی مثل “س”، “ئ”، “و” اصلاً w (کاراکتر کلمه) نیستن! اونها مثل “!” و “@” و ” ” (فاصله) همگی W (کاراکتر غیر-کلمه) در نظر گرفته میشن.
سناریو:
تو میخوای کلمهی “سئو” رو در متن “آموزش سئو” پیدا کنی.
الگو: bسئوb
نتیجه: پیدا نمیکنه!
چرا؟
قبل از “س“: موتور میخواد b رو بین ” ” (فاصله) و “س” پیدا کنه.
کاراکتر قبلی: ” ” (که W است).
کاراکتر بعدی: “س” (که اونم W در نظر گرفته میشه!).
نتیجه: W و W مرز کلمه (b) نیستن. پس b تطبیق داده نمیشه.
راهحل چیست؟
فعال کردن Unicode Mode: در زبانهایی مثل پایتون یا جاوا اسکریپت (ES2018 به بعد)، میتونی “فلگ” یا “حالت یونیکد” رو فعال کنی (مثلاً فلگ u در جاوا اسکریپت: /bسئوb/u). این کار به موتور Regex میگه که حروف یونیکد (مثل فارسی) رو هم به عنوان w بشناس.
استفاده از جایگزینها: اگه به حالت یونیکد دسترسی نداری، باید b رو فراموش کنی و از جایگزینهای قدرتمندتری مثل Lookarounds استفاده کنی.
جایگزینهای b برای سناریوهای پیچیده (مانند Lookarounds)
وقتی b کار نمیکنه (به خاطر آندرلاین، خط تیره، یا زبان فارسی)، تو به ابزار دقیقتری نیاز داری: Lookarounds.
Lookaroundها هم مثل b «صفر-پهنا» هستن. یعنی فقط یک موقعیت رو چک میکنن و کاراکتری رو مصرف نمیکنن.
(?=…): Lookahead (نگاه به جلو) مثبت. مطمئن میشه که متن بعدی مطابق الگو باشه.
(?!…): Lookahead (نگاه به جلو) منفی. مطمئن میشه که متن بعدی مطابق الگو نباشه.
(?<=…): Lookbehind (نگاه به عقب) مثبت. مطمئن میشه که متن قبلی مطابق الگو باشه.
(?<!…): Lookbehind (نگاه به عقب) منفی. مطمئن میشه که متن قبلی مطابق الگو نباشه.
چطور باLookaroundیک bدستی بسازیم؟
فرض کن میخوایم b رو برای زبان فارسی شبیهسازی کنیم و کلمهی “سئو” رو پیدا کنیم. (با فرض اینکه حروف فارسی [ا-ی] هستن).
الگوی دستی: (?<![ا-ی])سئو(?![ا-ی])
تحلیل الگو:
(?<![ا-ی]): “نگاه به عقب منفی”. مطمئن شو که کاراکتر قبلی، حرف فارسی نیست. (این معادل b در اول کلمه است).
سئو: خودِ کلمه.
(?![ا-ی]): “نگاه به جلو منفی”. مطمئن شو که کاراکتر بعدی، حرف فارسی نیست. (این معادل b در آخر کلمه است).
این الگو خیلی دقیقتر از b عمل میکنه و مشکل یونیکد و آندرلاین و همهچیز رو حل میکنه، چون تو خودت تعریف کردی که «مرز» دقیقاً یعنی چی.
جمعبندی: چه زمانی از b استفاده کنیم (و چه زمانی نه)؟
حالا که همهی اینها رو میدونی، میتونیم یک چکلیست ساده داشته باشیم:
چه زمانی از bاستفاده کنیم؟
وقتی با متنهای انگلیسی (ASCII) و ساده سروکار داری.
وقتی میخوای کلمات کامل رو در ابزارهایی مثل گوگل آنالیتیکس یا سرچ کنسول فیلتر کنی (این ابزارها معمولاً b رو به خوبی پشتیبانی میکنن).
وقتی میخوای کلمهای رو پیدا کنی و برات مهمه که به نقطه یا ویرگول ختم شده باشه (مثلاً bcatb کلمهی “cat.” رو پیدا میکنه).
وقتی در زبان برنامهنویسی خودت، حالت Unicode رو فعال کردی و مطمئنی که حروف فارسی رو به عنوان w میشناسه.
چه زمانی باید از bدوری کنیم (و ازLookaroundsاستفاده کنیم)؟
وقتی با زبان فارسی سروکار داری و از پشتیبانی موتور Regex از یونیکد مطمئن نیستی.
وقتی “کلمه”ی مورد نظر تو شامل آندرلاین (_) هست (مثلاً my_word). b در این حالت شکست میخوره.
وقتی میخوای کلمهای که شامل خط تیره (-) هست (مثل seo-friendly) رو به عنوان یک واحد در نظر بگیری. b وسطش رو به عنوان مرز میشناسه.
وقتی به تعریف بسیار دقیقتری از «مرز» نیاز داری (مثلاً: “فقط کلماتی که قبلشون فاصله و بعدشون نقطه اومده”).
جمعبندی
خب، تبریک میگم! تو حالا فقط نمیدونی b چیه، بلکه دقیقاً درک کردی که موتور Regex چطور «مرز» رو تشخیص میده، چطور ازش در پایتون و جاوا اسکریپت استفاده کنی و مهمتر از همه، چطور چالشهای رایجش مثل مشکل با آندرلاین یا زبان فارسی رو با ابزارهای دقیقتری مثل Lookarounds حل کنی.
یادت باشه، b دوست توئه تا جستجوهای تمیز و دقیقی داشته باشی. استفاده از bcatb به جای “cat” تفاوت بین یک تحلیلگر دادهی حرفهای و یک مبتدی رو نشون میده. از امروز، با این ابزار قدرتمند، کنترل کامل متنها و دادهها در دست توئه.
سوالات متداول (FAQ)
۱. آیا bهمان فاصله (Space) است؟
نه، این رایجترین اشتباهه! b یک کاراکتر مثل فاصله نیست، بلکه یک «موقعیت صفر-پهنا» است. b فقط چک میکنه که جنس کاراکترهای دو طرفش متفاوت باشه (یکی w و یکی W). برای همین bcatb میتونه “cat.” (که به نقطه چسبیده) رو هم پیدا کنه.
۲. چرا bبا کلمات فارسی کار نمیکند؟
چون در حالت پیشفرض، خیلی از موتورهای Regex حروف فارسی رو جزو w (کاراکتر کلمه) حساب نمیکنن و اونها رو W (مثل نقطه و ویرگول) در نظر میگیرن. برای حل این مشکل، یا باید حالت Unicode رو فعال کنی (اگه موتورت پشتیبانی میکنه، مثل فلگ u در جاوا اسکریپت) یا از جایگزینهای دقیقتری مثل Lookarounds (مثلاً (?<![ا-ی])کلمه(?![ا-ی])) استفاده کنی.
۳. چرا bکلمهی من که آندرلاین (_) دارد را پیدا نمیکند؟
چون آندرلاین (_) رسماً جزو w (کاراکتر کلمه) تعریف شده (در کنار حروف و اعداد). بنابراین، در “my_word”، موقعیت قبل و بعد از آندرلاین، B (نبود مرز) محسوب میشه، چون هر دو طرفش (y و w) از جنس w هستن. b در اینجا مرزی تشخیص نمیده.