img

عبارت های با قاعده در C++

/
/
/

در این مقاله به بررسی عبارت های با قاعده (regular expressions) در زبان برنامه نویسیِ C++ می پردازیم. عبارت های با قاعده، در علوم رایانه به معنی تطبیق رشته در متن است که از آن ها می توان به نویسه (کاراکتر) ها، کلمه ها و الگو هایِ نویسه اشاره کرد. یک عبارت با قاعده با زبان معمولی نوشته می شود که می تواند به وسیله یک پردازشگر عبارت با قاعده یا یک برنامه که به عنوان تولید کننده کامپایلر (ویرایش گر یا مترجم) یا بررسی کننده متن و تشخیص قسمت هایی از آن به وسیله مشخصات، استفاده شود.
در بیشتر موارد در زبان های ترجمه شده، متغیر ها به شکل ضعیفی تایپ شده اند تا نیازی به توضیح قبلی نداشته باشند. یکی دیگر از ویژگی های متغیر هایی که ضعیف تایپ شده اند این است که می توانند برای نگه داری از انواع مختلف داده ها به کار برده شوند. برای نمونه، یک متغیر یکسان می تواند نگه دارنده یک عدد صحیح (integer)، یک نویسه (character) یا یک رشته (string) باشد. با توجه به این ویژگی ها، بیشتر متن هایی که در چنین زبان هایی نوشته می شوند، بسیار فشرده هستند. البته این شرایط در مورد زبان های ترجمه یا ویرایش شده (compiled) که در آن ها به مقدار دِهی و فُرمت ابتدایی نیاز داریم، متفاوت است. اگر ترکیب عبارت های با قاعده (regular expression syntax) برای زبان های ویرایش شده و ترجمه شده، یکسان هم باشد، چگونگیِ استفاده از آن ها در برنامه های واقعی متفاوت است. بنا بر این، در این مقاله، ترکیب عبارت های با قاعده C++ را بررسی می کنیم.

 

استاندارد های C++
مردم در بیشتر موارد به این حقیقت که زبان های برنامه نویسی مانند C و C++ دارای استاندارد های متفاوتی هستند، توجهی ندارند. در حقیقت این دو زبان برنامه نویسی مانند زبان های Perl و Python از هر نظر متفاوت هستند و در هر کدام از آن ها، با توجه به طبیعتشان، باید از عبارت های با قاعده خودشان استفاده کرد (این ها زبان های پردازه نویسی یا Scripting هستند که به طور گسترده برای پردازش متن و توسعه اپلیکیشن های وِب مورد استفاده قرار می گیرند).
برای زبانی مانند C++ که به طور وسیع و گسترده ای برای اپلیکیشن های محاسباتیِ عملکرد بالا، برنامه ریزی سیستم، توسعه سیستم پیاده شده و مواردی مانند این ها استفاده می شود، این احساس به وجود می آید که وارد کردن عبارت های با قاعده، غیر ضروری بوده است. حقیقت این است که بسیاری از استاندارد های ابتداییِ C++ دارای یک روش طبیعی برای اداره کردن عبارت های با قاعده نبوده اند. در این مقاله، البته به صورت مختصر، استاندارد های متفاوت C++ و آن هایی که در میان این استاندارد ها دارای پشتیبانی از عبارت های با قاعده هستند را بررسی می کنیم.
زبان C++ توسط بیارنه اِستراستروپ (Bjarne Stroustrup) در سال ۱۹۷۹ میلادی ایجاد شد و در ابتدا با نام C با کلاس (C with Classes) شناخته می شد تا این که در سال ۱۹۸۳ نام آن به C++ تغییر کرد. کتابی با عنوان زبان برنامه نویسیِ C++ (با عنوان انگلیسیِThe C++ Programming Language) برای نخستین بار در ۱۹۸۵ توسط خودِ اِستراستروپ چاپ شد و ویرایش بعدی آن با نام de facto برای C++ تا سال ۱۹۹۸ و زمانی که این زبان توسط سازمان بین المللی استاندارد سازی (ISO مخفف The International Organization for Standardization) و کمیسیون الکترونیکی بین المللی (IEC مخفف International Electrotechnical Commission) به عنوان ISO/IEC 14882:1998 استاندارد سازی شد و به صورت غیر رسمی C++98 نام گُذاری شد، چاپ نشده بود. سه استاندارد بعدیِ C++ به صورت غیر رسمی به ترتیب C++03، C++11 و C++14 نام گذاری شدند. امیدواریم که در زمان چاپ شدن این مقاله، آخرین استاندارد C++ که به صورت غیر رسمی به C++17 معروف شده است ارائه شده باشد. استاندارد بعدی که به C++20 معروف است در سال ۲۰۲۰ میلادی ارائه خواهد شد.
سه استاندارد ابتدایی C++، که با نام استاندارد های de facto برای C++، C++98 و C++03 شناخته می شوند، هیچ ساز و کار (مکانیسم) داخلی (تو کار یا inbuilt) برای مدیریت عبارت های با قاعده نداشتند. در C++11 و زمانی که پشتیبانیِ طبیعی برای عبارت های با قاعده اضافه شد با کمک یک فایل عنوان (header file) جدید به نام <regex>، همه چیز تغییر کرد. در حقیقت، پشتیبانی از عبارت های با قاعده یکی از مهم ترین تغییراتی بود که در این استاندارد وجود داشت. همچنین، C++14 نیز دارای پشتیبانی طبیعی از عبارت های با قاعده بوده و بسیار عجیب خواهد بود که در C++17 و استاندارد های بعدیِ C++، پشتیبانی از کنترل عبارت های با قاعده، وجود نداشته باشد. یکی از مشکلاتی که ممکن است در این زمینه وجود داشته باشد این است که انجمن علمی در هند بیشتر بر اساس استاندارد C++98 حرکت می کند که از عبارت های با قاعده پشتیبانی نکرده است. البته این یک نظر شخصی است و مدرکی برای اثبات آن وجود ندارد.

 

استاندارد C++11
بر خلاف C++03 و C++14، که تغییرات در آن ها کمترین مقدار ممکن بود، C++11 یک بازنگریِ اساسی و کُلی برای C++ به حساب می آمد. در حقیقت GCC5 به صورت کامل از ویژگی های C++11 و C++14 پشتیبانی می کرد که این آخری، به استاندارد پیش فرض برای GCC 6 تبدیل شُد. در استاندارد C++11، تغییرات زیادی بر روی زبان اصلی انجام شد. ورودیِ یک نوع داده عدد صحیح ۶۴ بیتیِ long long int، همان تغییری بود که توسط استاندارد C++11 در C++ ایجاد شده بود. پیش از این، C++ فقط دارای عدد های صحیح ۳۲ بیتی با نام long int بود. همچنین، اُلگو های خارجی (external templates) نیز توسط همین استاندارد به C++ اضافه شده بود.
تغییرات زیاد دیگری با استاندارد C++11 در هسته زبان C++ ایجاد شدند اما تغییرات تنها محدود به هسته برنامه نبودند و کتابخانه استاندارد C++ نیز در استاندارد C++11 بهبود پیدا کرد. تغییرات در کتابخانه استاندارد C++ به شکلی انجام شده بود که رشته های اجرایی چند گانه (multiple threads) می توانستند به سادگی ایجاد شوند. روش های جدید برای تولید عدد های شبه تصادفی (pseudo-random numbers) نیز در استاندارد C++11 تامین شده بودند. یک روش یکسان برای محاسبه نحوه بازگشت اشیاء تابع (function objects) نیز در استاندارد C++11 وجود داشت. اگر چه تغییرات بسیار زیادی در کتابخانه استاندارد در C++11 ایجاد شده بود اما چیزی که بیشتر از همه جلب توجه می کرد، ورود یک فایل عنوان (header file) جدید با نام <regex> بود.

 

عبارت های با قاعده C++11
در C++، پشتیبانی از عبارت های با قاعده با ایجاد تغییرات در کتابخانه استاندارد C++ به دست آمده است. فایل عنوانی که با نام <regex> شناخته می شود به کتابخانه استاندارد C++ اضافه شد تا از عبارت های با قاعده پشتیبانی شود. فایل عنوان <regex> در استاندارد C++14 نیز وجود دارد پس چیزی که ما در C++11 تجربه کردیم در C++14 هم به کار برده می شود. چیز های دیگری به فایل عنوان <regex> در C++14 اضافه شده که در ادامه به آن ها می پردازیم. سه تابع وجود دارند که توسط فایل عنوان <regex> ایجاد و پشتیبانی شده اند. این تابع ها عبارت از regex_match، regex_search و regex_replace هستند. تابع regex_match تنها زمانی یک هَمتا یا نظیر (match) را بر می گرداند که آن همتا در ابتدای رشته (string) وجود داشته باشد در حالی که regex_search تمام رشته (string) را برای یک همتا (match) جستجو می کند. تابع regex_replace در کنار این که همتا (match) را پیدا می کند، رشته (string) همتا را با رشته (string) جانشین، عوض می کند. همه این تابع ها برای نشان دادن رشته ای که باید تطبیق پیدا کند (match شود)، از عبارت های با قاعده استفاده می کنند.
علاوه بر این سه تابع، فایل عنوان <regex> چندین کلاس مانند regex و wregex و همچنین چند نوع تکرار (iterator، یک شیء که به برنامه نویس ها کمک می کند تا یک مجموعه، به خصوص لیست ها را حرکت دهند) مانند regex_iterator و regex_token_iterator را نیز تعریف می کند. اما برای ساده تر کردن و البته کوتاه تر کردن مقاله، فقط کلاس regex و سه تابع regex_search، regex_match و regex_replace را بررسی می کنیم. بررسی تمام ویژگی های فایل عنوان <regex> در یک مقاله کوتاه امکان پذیر نیست اما موضوع هایی که مطرح می شوند، می توانند شروع خوبی برای برنامه نویس های جدیِ C++ باشند تا به سطح کاربران حرفه ای در استفاده از عبارت های با قاعده برسند. در ادامه، چگونگیِ استفاده از عبارت های با قاعده در C++ را با استفاده از یک برنامه کوچک C++ بررسی می کنیم.

یک برنامه ساده C++ با استفاده از عبارت های با قاعده
کُد زیر یک برنامه C++ به نام regex.1.cc را نشان می دهد. بدون تردید با پسوند .cc در برنامه های C++ آشنا هستید. این برنامه و تمام برنامه های C++ دیگری که در این مقاله استفاده می شوند را می توانید به همراه تمام فایل های متنیِ استفاده شده، از

http://opensourceforu.com/article_source_code/September17C++.zip

دانلود کنید.

#include <iostream>
#include <regex>
using namespace std;
int main( )
{
char str[ ] = “Open Source For You”;
regex pat(“Source”);
if( regex_search(str,pat) )
{
cout << “Match Found\n”;
}
else
{
cout<<”No Match Found\n”;
}
return 0;
}

 

فرض می کنیم ترکیبِ (syntax) C برای خوانندگان از هر نظر شناخته شده است. در حقیقت تنها کافی است برنامه های C++ مورد بررسی در این مقاله را به سادگی درک کنید و بیشتر از این به هیچ مهارت دیگری نیاز ندارید. اکنون به تجزیه و تحلیل این برنامه می پردازیم. دوخط ابتدایی #include <iostream> و #include <regex> شامل دو فایل عنوان <iostream> و <regex> هستند. خط بعدیِ کُد یعنی using namespace std;، کار اضافه کردن std namespace به برنامه را انجام داده تا cout، cin و مواردی مانند آن ها بتوانند بدون کمک اُپراتور رزولوشِن محدوده (scope resolution operator) که با علامت :: نشان داده می شود، مورد استفاده قرار بگیرند. خط int main اعلام می کند که تنها تابع این برنامه، تابع main است.
یکی از مشکلاتی که در زمان استفاده از زبان های برنامه نویسیِ C++ یا Java با آن ها روبرو می شویم، همین است. شما باید تعداد زیادی کُد برای انجام تنظیمات محیط و به حرکت در آوردن چیز ها بنویسید. این یکی از دلیل هایی است که چرا در زمان پردازش یک فایل متنی (text) باید با زبان هایی مانند Perl یا Python به جای C++ یا Java کار کنید. اما اگر در حال نوشتن نرم افزار سیستم هستید و می خواهید یک فایل ثبت (log file) سیستم را تجزیه و تحلیل کنید، استفاده از عبارت های با قاعده در C++ یک ایده بسیار عالی به حساب می آید.
خط بعدیِ کُد، char str[] = «Open Source For You»;، مقدار دهیِ ابتداییِ یک آرایه نویسه (character array) به نام str[] به همراه یک رشته (string) در آن را انجام می دهد که ما در آن به جستجوی یک اُلگو (pattern) می پردازیم. در این موردِ خاص، مقدار دهیِ ابتداییِ این آرایه نویسه با رشته Open Source For You انجام شده است. اگر بخواهید خطِ کُد char str[] = Open Source For You را با رشته str = «Open Source For You»; جایگزین کرده و در نتیجه از شیء str در کلاس رشته C++ به جای یک آرایه نویسه استفاده کنید، برنامه باز هم به درستی کار خواهد کرد. به خاطر داشته باشید کلاس رشته (string) در C++ فقط یک نمونه از کلاس الگو (template) از نوع basic_string است.
این برنامه بهبود داده شده که string.cc نام دارد را نیز می توانید دانلود کنید. با اجرای فرمان (command) های g++ string.cc و ./a.out برای برنامه string.cc می بینید که این برنامه نیز درست مانند برنامه regex1.cc کار می کند. از آن جایی که ممکن است خوانندگان این مقاله گروه مختلفی از برنامه نویسان متخصص در زبان های برنامه نویسیِ مختلف باشند، در این مقاله تلاش شده است که C++ تا جایی که ممکن است شبیه زبان برنامه نویسیِ C باشد چرا که C زبانی دانشگاهی و علمی بوده و هر برنامه نویسی در زمان تحصیل خود با آن آشنا شده است. می توانستیم از تابع های printf و scanf به جای cout و cin استفاده کنیم. اما یک خط باید در جایی تمام شود و این همان جایی است که شبیه کردن C++ به C را تمام می کنیم.
خط بعدیِ کُد regex pat(«Source»);، بسیار مهم است. این خط مسئولیت تنظیم الگوی عبارت های با قاعده ای که باید در رشته Open Source For You جستجو شوند را دارد. در این جا، الگوی جستجو شده، کلمه ‹Source› که در یک شیء به نام pat در کلاس regex ذخیره شده است می باشد.
چند خط بعدیِ کُد شامل یک عبارت if-else است. خطِ کُدِ if( regex_search(str,pat) ) از تابع regex_search تامین شده توسط فایل عنوان <regex> برای جستجوی اُلگوی (pattern) ذخیره شده در شیء pat در کلاس regex و در رشته ذخیره شده در داخل آرایه نویسه str[]، استفاده می کند. اگر هیچ همتایی (match) پیدا نشود، خطِ کُدِ cout<< «No Match Found\n»; اجرا شده و پیام No Match Found (به معنی هیچ همتایی پیدا نشد) بر روی صفحه نمایش چاپ می شود. این برنامه می تواند با فرمان g++ regex1.cc که در آن g++، ویرایش (compile) کننده C++ تامین شده توسط GCC (مخفف GNU Compiler Collection به معنیِ مجموعه ویرایش کننده GNU) است، ویرایش (compile) شود. با این کار، یک برنامه قابل اجرا با نام a.out ایجاد شده و پس از آن با فرمان ./a.out اجرا می شود. در زمان اجرا، برنامه به دلیل این که تابع regex_search تمام رشته را برای پیدا کردن یک همتا جستجو کرده، پیغام Match Found (به معنیِ همتا پیدا شد) را بر روی صفحه نمایش چاپ می کند. از آن جایی که کلمه Source در رشته Open Source For You وجود دارد، یک همتا (match) پیدا شده است.
اکنون، زمان آن رسیده تا نگاهی دوباره به تفاوت بین تابع های regex_search و regex_match داشته باشیم. برای انجام این کار، خطِ کُدِ if( regex_search(str,pat) ) در برنامه regex1.cc با خط if( regex_match(str,pat)) جایگذاری شده است.
این کُد بهبود داده شده به عنوان برنامه ای با نام regex2.cc در دسترس است که می تواند با فرمان g++ regex2.cc ویرایش شده و برنامه قابل اجرایی با نام a.out را تولید کرده و پس از آن با فرمان ./a.out اجرا می شود. اکنون، خروجی نمایش داده شده (چاپ شده) بر روی صفحه نمایش، پیام No Match Found (به معنی هیچ همتایی پیدا نشد) است. چرا؟ همان طور که پیش از این اشاره کردیم، این موضوع به دلیل تفاوت بین تابع های regex_search و regex_match است. تابع regex_search تمام رشته را برای پیدا کردن یک همتا (match) جستجو می کند در حالی که تابع regex_match تنها زمانی نتیجه درست (true) را بر می گرداند که اُلگوی عبارت با قاعده در ابتدای یک رشته باشد. در این مورد، کلمه Source به عنوان دومین کلمه در رشته Open Source For You آورده شده و بنا بر این هیچ همتایی توسط تابع regex_match پیدا نشده است. شکل ۱، خروجیِ برنامه های regex1.cc و regex2.cc را نشان می دهد.

 

جایگزینیِ اُلگو در C++
اکنون به برررسی عملکرد تابع regex_replace می پردازیم. برنامه regex3.cc که از تابع regex_replace استفاده می کند را در نظر بگیرید. این تابع یک همتا (match) را جستجو کرده و در صورت پیدا کردن آن، رشته همتا (match) شده را با رشته جایگزین (replacement string)، جابجا می کند.

#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main( )
{
char str[ ] = “Open Source Software is Good”;
regex pat(“Open Source”);
char rep[ ] = “Free”;
cout <<regex_replace(str,pat,rep)<<’\n’;
return 0;
}

 

به غیر از خط کُدِ

<<regex_replace(str,pat,rep)<<›\n›;

به نظر نمی رسد که به توضیح بیشتری نیاز داشته باشیم. این همان خطی است که تابع regex_replace به همراه سه پارامتر دیگر خوانده می شود. این پارامتر ها عبارت از آرایه نویسه str[] که رشته های جستجو شده در آن ذخیره شده، اُلگوی (pattern) عبارت های با قاعده برای ذخیره کردن همتا در شیء pat کلاس regex و اُلگویی برای ذخیره کردن جایگزین ها در آرایه نویسه rep[]، هستند. برنامه regex3.cc را با فرمان های g++ regex3.cc و ./a.out اجرا کنید. شما پیام Free Software is Good را بر روی صفحه نمایش مشاهده خواهید کرد. هیچ چیز عجیبی وجود ندارد چرا که رشته در آرایه نویسه str[] شامل Open Source Software is Good است، الگویی که جستجو می شود Open Source بوده و الگوی جایگزین Free می باشد. بنا بر این، یک همتا (match) پیدا شده و یک جایگزینی به وسیله تابع regex_replace انجام شده است.
پُرسش بعدی که باید جواب آن داده شود این است که آیا تابع regex_replace مانند تابع regex_search یا تابع regex_match کار می کند یا عملکرد متفاوتی دارد. برای درکِ بهترِ رفتار تابع regex_replace، برنامه regex3.cc را بهبود داده و برنامه ای به نام regex4.cc (که در ادامه می بینید) را به دست می آوریم:

#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main( )
{
char str[ ] = “Open Source Software is Good”;
regex pat(“Good”);
char rep[ ] = “Excellent”;
cout <<regex_replace(str,pat,rep)<<’\n’;
return 0;
}

بعد از اجرا کردن برنامه regex4.cc با فرمان های g++ regex4.cc و ./a.out، پیام Open Source Software is Excellent (بر روی صفحه نمایش) چاپ می شود. مشخص است که تابع regex_replace مانند تابع regex_search کار می کند چرا که تمام رشته برای پیدا کردن یک همتا برای عبارت با قاعده داده شده، جستجو می شود. همان طور که اشاره شد، بر خلاف این دو تابع، تابع regex_match، وجودِ یک همتا در شروع رشته را بررسی می کند. شکل ۲، خروجیِ دو برنامه regex3.cc و regex4.cc را نشان می دهد.

 

پردازش فایل در C++ با استفاده از عبارت های با قاعده
پرسش بعدی برای جواب دادن این است که چگونه می توانیم داده ها را در داخل یک فایل متنی با یک عبارت با قاعده، پردازش کنیم؟ برای بررسی چگونگیِ کار کردن چنین برنامه ای، از یک فایل متنیِ (text) به نام file1.txt استفاده می کنیم.

unix is an operting system
Unix is an Operating System
UNIX IS AN OPERATING SYSTEM
Linux is also an Operating System

 

اکنون برنامه C++ زیر که regex5.cc نام دارد را در نظر می گیریم. این برنامه، فایل متنیِ file1.txt را خط به خط خوانده و اجرا می کند تا تمام خط هایی که شامل کلمه UNIX است را چاپ کند.

using namespace std;
int main( )
{
ifstream file(“file1.txt”);
string str;
regex pat(“UNIX”);
while (getline(file, str))
{
if( regex_search(str,pat) )
{
cout << str <<”\n”;
}
}
return 0;
}

 

وقتی برنامه regex5.cc با فرمان های g++ regex5.cc و ./a.out اجرا شود، پیام UNIX IS AN OPERATING SYSTEM بر روی صفحه نمایش چاپ می شود. بنا بر این، در این جا یک همتایِ اُلگوی حساس به مورد (case-sensitive pattern match)، اجرا شده است. پرسش بعدی این است که چگونه یک همتایِ اُلگوی غیر حساس به مورد را اجرا کنیم؟ برای این کار، از یک ثابت regex به نام icase استفاده می کنیم. وقتی خطِ کُدِ regex pat(«UNIX»); با خط regex pat(«UNIX», regex_constant::icase); جایگزین شود، یک همتایِ غیر حساس به مورد اجرا شده که نتیجه آن یک همتا برای سه خط در فایل متنیِ file1.txt است. شکل ۳، نتیجه های همتا های غیر حساس به مورد و حساس به مورد را نشان می دهد. ثابت های regex زیادی در فضای نام (namespace که محیط ایجاد شده برای انجام گروه بندیِ منطقی از شناسه های یِکتا یا نماد است) regex_constants تعریف شده اند که برخی از آن ها عبارت از nosubs، optimize و collate هستند. استفاده از ثابت های regex، قدرت و کارایی بیشتری به عبارت های با قاعده دهد. اگر می خواهید اطلاعات بیشتری درباره عبارت های با قاعده به دست بیاورید، بهتر است درباره این ثابت ها هم مطالعه کنید.

 

عبارت های با قاعده در C++14 و C++17
اکنون وقت آن است که عبارت های با قاعده در C++14 را بررسی کنیم. خوش بختانه، به غیر از چند مورد کوچکی که اضافه شده است، فایل عنوان <regex> در C++11 بعد از معرفیِ استاندارد C++14 نیز تغییرات زیادی نداشته است. برای نمونه، تعریف تابع های regex_match و regex_search تنها کمی در C++14 بهبود داده شده اند تا پردازشِ بیشتر با این تابع ها امکان پذیر باشد. اما این تغییرات تنها قدرت و کاریی بیشتری به تابع های موجود اضافه کرده و اثری بر روی چگونگیِ عملکرد (پایه ای) و کاراییِ آن ها نداشته است. آخرین نکته این است که چه تغییراتی در استاندارد C++17 ایجاد می شود؟ امیدواریم تغییرات مهم و اساسی در کار نباشند. تا کنون، شایعه ای درباره این که تغییرات اساسی و مهمی بر روی فایل عنوان <regex> انجام شده، شنیده نشده است. بنا بر این، می توانیم از هر چیزی که در این مقاله یاد می گیریم، دستِ کم برای مدتی طولانی استفاده کنیم.

 

سبک عبارت های با قاعده C++
در این مقاله از ابتدا به توضیح عبارت های با قاعده پرداختیم بدون این که نگاهی به ترکیب (syntax) یک عبارت با قاعده مورد استفاده در C++ داشته باشیم. در برخی موارد، بهتر است به جای این که توضیح اضافی بدهیم، مستقیم به سراغ اصل مطلب برویم. در مورد توضیح عبارت های با قاعده، ما از این روش استفاده کردیم اما بدون تردید لازم است که ترکیب (syntax) عبارت های با قاعده به کار رفته در C++ را نیز بشناسیم زیرا در غیر این صورت این مقاله به یک مجموعه راهنما های «خودتان انجام دهید» (Do-It-Yourself) تبدیل می شود. عبارت های با قاعده C++11 از سبک های عبارت با قاعده چندگانه مانند ECMAScript syntax، AWK script syntax و Grep syntax پشتیبانی می کنند.
همان طور که می دانید، ECMAScript یک زبان پردازه (script) نویسی بوده و JavaScript نیز شناخته شده ترین پیاده سازیِ ECMAScript است. ترکیب استفاده شده به وسیله ECMAScript تفاوت چندانی با دیگر عبارت های با قاعده ندارد. در حقیقت تفاوت آن ها در چند مورد کوچک است. برای نمونه، علامت گذاریِ \d که در عبارت های با قاعده سبک Perl برای مشخص کردن عدد های اعشاری (decimal) استفاده می شود، در عبارت های با قاعده سبک ECMAScript، حذف شده و به جای آن از یک علامت گذاری مانند [[:digit:]] استفاده می شود. در این مقاله نمی خواهیم به تفاوت های بیشتری در مورد سبک عبارت های با قاعده در زبان های مختلف اشاره کنیم اما به خاطر داشته باشید که C++11 از سبک های عبارت با قاعده چند گانه پشتیبانی کرده و برخی از سبک ها با هم، تفاوت های کوچکی دارند.

 

عبارت های با قاعده کاربردی برای C++
در این قسمت به بررسی یک عبارت با قاعده کاربردی می پردازیم که با استفاده از آن می توانیم به جای پیدا کردن رشته های شروع شده با abc و تمام شده با xyz، داده ها و اطلاعات واقعی را پیدا کنیم. هدف ما شناساییِ آن خط هایی است که فقط دارای عدد هستند. فایل متنِ file2.txt را با داده های زیر برای بررسی عبارت های با قاعده خودمان در نظر بگیرید:

abcxyz
a1234z
۱۱۱۲۲۲
۱۲۳۴۵۶
aaaaaaa
zzzzzzz
AA111
۱۱۱
۲۲۲۲
۳۳۳۳۳
۲۲٫۲۲
BBBB

 

حالا برنامه regex7.cc را با کُد های زیر نظر بگیرید:

#include <iostream>
#include <string>
#include <fstream>
#include <regex>
using namespace std;
int main()
{
ifstream file(“file2.txt”);
string str;
regex pat(“^[[:digit:]]+$”);
while (getline(file, str))
{
if( regex_search(str,pat) )
{
cout << str <<”\n”;
}
}
return 0;
}

 

بعد از اجرای برنامه با استفاده از فرمان های g++ regex7.cc و ./a.out می بینیم که برنامه فقط خط هایی که دارای عدد هستند را چاپ کرده است. شکل ۴، خروجیِ برنامه regex7.cc را نشان می دهد.
به غیر از خطِ کُدِ regex pat(«^[[:digit:]]+$›); که اُلگوی عبارت با قاعده ای که جستجو می شود را تعریف می کند، تفاوتی بین عملکرد برنامه های regex5.cc و regex7.cc وجود ندارد. علامت ^ برای علامت گذاری همتایی (match) که باید در ابتدا وجود داشته باشد و علامت $ برای علامت گذاریِ همتایی (match) که باید در انتها وجود داشته باشد استفاده شده است. عبارت با قاعده [[:digit:]]+ که به وجود یک یا چند عدد اعشاری اشاره دارد، مانند [۰-۹]+ است. بنا بر این، عبارت با قاعده داده شده، فقط در شرایطی یک همتا را پیدا می کنند که خطِ متن تنها دارای عدد های اعشاری باشد. به همین دلیل، خط های متن مانند AA111، ۲۲٫۲۲، a1234z و خط های مشابه انتخاب نشده اند.
در انتهای مقاله، مطالب بیان شده را جمع بندی می کنیم. در این مقاله، چگونگیِ استفاده از عبارت های با قاعده و جنبه های دیگری که در استفاده از عبارت های با قاعده در زبان برنامه نویسیِ C++ اثر گذار هستند را بررسی کردیم. همچنین، به طور کامل درباره استاندارد های C++، که برای استفاده هدفمند و دقیق از عبارت های با قاعده ضروری هستند، بدون در نظر گرفتن تفاوت های ساختاری آن ها صحبت کردیم تا شما بتوانید با درک بهتری از آن ها استفاده کنید. ممکن است مطالب مطرح شده در مورد عبارت های با قاعده در این مقاله، کامل نباشند اما می توانند مقدمه ای خوب برای برنامه نویس های C++ بوده و به عنوان نقطه شروعی برای مطالعه بیشتر و دقیق تر در نظر گرفته شوند.

نظر بدهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

It is main inner container footer text