یک عبارت منظم (regex) چیست؟
در واقع یک عبارت منظم الگویی برای یافتن یک رشته در متن است. در جاوا، نمایش اصلی این الگو همیشه یک رشته، یعنی یک شی ازStringکلاس است. با این حال، هیچ رشته ای نیست که بتوان به یک عبارت منظم کامپایل کرد - فقط رشته هایی که با قوانین ایجاد عبارات منظم مطابقت دارند. نحو در مشخصات زبان تعریف شده است. عبارات منظم با استفاده از حروف و اعداد و همچنین متاکاراکترها نوشته می شوند که کاراکترهایی هستند که معنای خاصی در نحو عبارت منظم دارند. مثلا:
String regex = "java"; // The pattern is "java";
String regex = "\\d{3}"; // The pattern is three digits;
ایجاد عبارات منظم در جاوا
ایجاد یک عبارت منظم در جاوا شامل دو مرحله ساده است:- آن را به صورت رشته ای بنویسید که با نحو عبارت منظم مطابقت دارد.
- رشته را به یک عبارت منظم کامپایل کنید.
Patternشی شروع می کنیم. برای این کار باید یکی از دو متد static کلاس را فراخوانی کنیم: compile. روش اول یک آرگومان می گیرد - یک رشته تحت اللفظی حاوی عبارت منظم، در حالی که روش دوم یک آرگومان اضافی را می گیرد که تنظیمات تطبیق الگو را تعیین می کند:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags) لیست مقادیر بالقوه
پارامتر flagsدر کلاس تعریف شده Patternو به عنوان متغیرهای کلاس ایستا در دسترس ما است. مثلا:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE); // Pattern-matching will be case insensitive. اساساً Patternکلاس سازنده ای برای عبارات منظم است. در زیر هود، compileمتد سازنده خصوصی کلاس را فراخوانی می کند Patternتا یک نمایش کامپایل شده ایجاد کند. این مکانیسم ایجاد شی به این روش به منظور ایجاد اشیاء تغییرناپذیر پیاده سازی می شود. هنگامی که یک عبارت منظم ایجاد می شود، نحو آن بررسی می شود. اگر رشته دارای خطا باشد، a PatternSyntaxExceptionایجاد می شود.
نحو عبارت منظم
نحو بیان منظم به<([{\^-=$!|]})?*+.>کاراکترها متکی است که می توانند با حروف ترکیب شوند. بسته به نقش آنها می توان آنها را به چند گروه تقسیم کرد:
| متاکاراکتر | شرح |
|---|---|
| ^ | ابتدای یک خط |
| $ | انتهای یک خط |
| \b | مرز کلمه |
| \ B | مرز غیر کلمه |
| \آ | ابتدای ورودی |
| \G | پایان مسابقه قبلی |
| \Z | انتهای ورودی |
| \z | انتهای ورودی |
| متاکاراکتر | شرح |
|---|---|
| \d | رقم |
| \ D | غیر رقمی |
| \s | کاراکتر فضای خالی |
| \S | کاراکتر بدون فضای سفید |
| \w | کاراکتر الفبایی یا زیرخط |
| \ W | هر کاراکتری به جز حروف، اعداد و خط زیر |
| . | هر شخصیت |
| متاکاراکتر | شرح |
|---|---|
| \ t | کاراکتر برگه |
| \n | شخصیت خط جدید |
| \r | برگشت محموله |
| \f | شخصیت خط تغذیه |
| \u0085 | کاراکتر خط بعدی |
| \u2028 | جداکننده خط |
| \u2029 | جداکننده پاراگراف |
| متاکاراکتر | شرح |
|---|---|
| [abc] | هر یک از کاراکترهای فهرست شده (a، b یا c) |
| [^abc] | هر کاراکتری غیر از موارد ذکر شده (نه a، b یا c) |
| [a-zA-Z] | محدوده های ادغام شده (نویسه های لاتین از a تا z، حساس به حروف کوچک و بزرگ) |
| [تبلیغ[mp]] | اتحاد کاراکترها (از a به d و از m تا p) |
| [az&&[def]] | تقاطع کاراکترها (d، e، f) |
| [az&&[^bc]] | تفریق کاراکترها (a, dz) |
| متاکاراکتر | شرح |
|---|---|
| ? | یکی یا هیچ کدام |
| * | صفر یا چند بار |
| + | یک یا چند بار |
| {n} | n بار |
| {n،} | n بار یا بیشتر |
| {n,m} | حداقل n بار و نه بیشتر از m بار |
کمیت کننده های حریص
چیزی که باید در مورد کمیت کننده ها بدانید این است که آنها در سه نوع مختلف وجود دارند: حریص، تملک و بی میل. شما با افزودن یک+کاراکتر " " بعد از کمیت، یک کمیت را مالکیت می کنید. با افزودن " " آن را بی میل می کنید ?. مثلا:
"A.+a" // greedy
"A.++a" // possessive
"A.+?a" // reluctant بیایید سعی کنیم از این الگو برای درک نحوه عملکرد انواع مختلف کمی سازها استفاده کنیم. به طور پیش فرض، کمیت کننده ها حریص هستند. این بدان معنی است که آنها به دنبال طولانی ترین مسابقه در رشته هستند. اگر کد زیر را اجرا کنیم:
public static void main(String[] args) {
String text = "Fred Anna Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
} این خروجی را می گیریم:
Anna Alexa برای عبارت منظم " A.+a"، تطبیق الگو به صورت زیر انجام می شود:
-
اولین کاراکتر در الگوی مشخص شده حرف لاتین است
A.Matcherبا شروع از شاخص صفر، آن را با هر کاراکتر متن مقایسه می کند. کاراکترFدر متن ما در شاخص صفر است، بنابراینMatcherاز طریق کاراکترها تکرار می شود تا زمانی که با الگو مطابقت داشته باشد. در مثال ما، این کاراکتر در شاخص 5 یافت می شود.![عبارات منظم در جاوا - 2]()
-
هنگامی که یک تطابق با کاراکتر اول الگو پیدا شد،
Matcherبه دنبال تطابق با کاراکتر دوم آن میگردد. در مورد ما، این.کاراکتر " " است که مخفف هر کاراکتری است.
شخصیت
nدر جایگاه ششم قرار دارد. مطمئناً به عنوان یک مسابقه برای "هر شخصیت" واجد شرایط است. -
Matcherبه بررسی کاراکتر بعدی الگو ادامه می دهد. در الگوی ما، در کمیتی که برای کاراکتر قبلی اعمال میشود، گنجانده شده است: ".+". از آنجا که تعداد تکرارهای "هر کاراکتری" در الگوی ما یک یا چند بار است،Matcherبه طور مکرر کاراکتر بعدی را از رشته می گیرد و تا زمانی که با "هر کاراکتری" مطابقت دارد، آن را با الگو بررسی می کند. در مثال ما - تا انتهای رشته (از شاخص 7 تا شاخص 18).
اساساً،
Matcherرشته را تا انتها می بلعد - این دقیقاً همان چیزی است که از "طمع" استفاده می شود. -
پس از اینکه Matcher به انتهای متن رسید و بررسی
A.+قسمت " " الگو را تمام کرد، شروع به بررسی بقیه الگو می کند:a. دیگر متنی در آینده وجود ندارد، بنابراین بررسی با «بازگشت» ادامه مییابد و از آخرین کاراکتر شروع میشود:![عبارات منظم در جاوا - 5]()
-
Matcherتعداد تکرارها را در.+قسمت " " الگوی "به خاطر می آورد". در این مرحله، تعداد تکرارها را یک بار کاهش می دهد و الگوی بزرگتر را در مقابل متن بررسی می کند تا زمانی که مطابقت پیدا شود:![عبارات منظم در جاوا - 6]()
کمیت کننده های مالکیتی
کمیت کننده های مالک بسیار شبیه به حریصان هستند. تفاوت در این است که وقتی متن تا انتهای رشته گرفته می شود، هیچ تطبیق الگو در حین "بازگشت" وجود ندارد. به عبارت دیگر، سه مرحله اول مانند کمی سازهای حریص است. پس از گرفتن کل رشته، تطبیق دهنده بقیه الگو را به آنچه در نظر می گیرد اضافه می کند و آن را با رشته ضبط شده مقایسه می کند. در مثال ما، با استفاده از عبارت منظم "A.++a"، متد اصلی هیچ مطابقتی پیدا نمی کند.
کمی سازهای بی میل
-
برای این کمیتکنندهها، مانند انواع حریص، کد به دنبال تطابق بر اساس اولین کاراکتر الگو میگردد:
![عبارات منظم در جاوا - 8]()
-
سپس به دنبال مطابقت با کاراکتر بعدی الگو (هر کاراکتری) میگردد:
![عبارات منظم در جاوا - 9]()
-
بر خلاف تطبیق الگوی حریصانه، کوتاهترین تطابق در تطابق الگوی بیمیل جستجو میشود. این به این معنی است که پس از یافتن یک تطابق با کاراکتر دوم الگو (یک نقطه، که با کاراکتر در موقعیت 6 متن مطابقت دارد،
Matcherبررسی میکند که آیا متن با بقیه الگو - کاراکتر " مطابقت دارد یا خیرa.![عبارات منظم در جاوا - 10]()
-
متن با الگو مطابقت ندارد (یعنی دارای کاراکتر "
n" در نمایه 7 است)، بنابراینMatcherیک "هر کاراکتر" بیشتری اضافه می کند، زیرا کمیت یک یا چند کاراکتر را نشان می دهد. سپس دوباره الگو را با متن در موقعیت های 5 تا 8 مقایسه می کند:![عبارات منظم در جاوا - 11]()
در مورد ما تطبیق پیدا می شود، اما هنوز به انتهای متن نرسیده ایم. بنابراین، تطبیق الگو از موقعیت 9 مجدداً شروع می شود، یعنی اولین کاراکتر الگو با استفاده از یک الگوریتم مشابه جستجو می شود و این کار تا پایان متن تکرار می شود.
mainروش هنگام استفاده از الگوی " A.+?a" نتیجه زیر را به دست می آورد: آنا الکسا همانطور که از مثال ما می بینید، انواع مختلف کمیت کننده ها نتایج متفاوتی را برای یک الگو تولید می کنند. پس این را در نظر داشته باشید و بر اساس آنچه به دنبال آن هستید، تنوع مناسب را انتخاب کنید.
فرار از کاراکترها در عبارات منظم
از آنجایی که یک عبارت منظم در جاوا، یا بهتر است بگوییم، نمایش اصلی آن، یک رشته واقعی است، ما باید قوانین جاوا را در مورد حروف رشته ای در نظر بگیریم. به طور خاص، کاراکتر بک اسلش "\" در رشته های literals در کد منبع جاوا به عنوان یک کاراکتر کنترلی تفسیر می شود که به کامپایلر می گوید که کاراکتر بعدی خاص است و باید به روش خاصی تفسیر شود. مثلا:
String s = "The root directory is \nWindows"; // Move "Windows" to a new line
String s = "The root directory is \u00A7Windows"; // Insert a paragraph symbol before "Windows" این بدان معنی است که حروف الفبای رشته ای که عبارات منظم را توصیف می کنند و از \کاراکترهای " " استفاده می کنند (یعنی برای نشان دادن متاکاراکترها) باید اسلش های معکوس را تکرار کنند تا اطمینان حاصل شود که کامپایلر بایت کد جاوا رشته را اشتباه تفسیر نمی کند. مثلا:
String regex = "\\s"; // Pattern for matching a whitespace character
String regex = "\"Windows\""; // Pattern for matching "Windows" برای فرار از کاراکترهای خاصی که می خواهیم به عنوان کاراکترهای "عادی" از آنها استفاده کنیم، باید از بک اسلش های دوگانه نیز استفاده شود. مثلا:
String regex = "How\\?"; // Pattern for matching "How?"
روش های کلاس الگو
کلاسPatternمتدهای دیگری برای کار با عبارات منظم دارد:
-
String pattern()‒ نمایش رشته اصلی عبارت منظم را که برای ایجادPatternشیء استفاده شده است، برمی گرداند:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.pattern()); // "abc" -
static boolean matches(String regex, CharSequence input)- به شما امکان می دهد عبارت منظم ارسال شده به عنوان regex را در مقابل متن ارسال شده به عنوان بررسی کنیدinput. برمی گرداند:درست - اگر متن با الگو مطابقت داشته باشد.
نادرست - اگر اینطور نیست؛مثلا:
System.out.println(Pattern.matches("A.+a","Anna")); // true System.out.println(Pattern.matches("A.+a","Fred Anna Alexander")); // false -
int flags()‒ مقدارflagsمجموعه پارامترهای الگو را هنگام ایجاد الگو یا 0 را اگر پارامتر تنظیم نشده بود، برمیگرداند. مثلا:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.flags()); // 0 Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE); System.out.println(pattern.flags()); // 2 -
String[] split(CharSequence text, int limit)- متن ارسال شده را به یکStringآرایه تقسیم می کند. پارامترlimitحداکثر تعداد منطبقات جستجو شده در متن را نشان می دهد:- اگر
limit > 0‒limit-1مطابقت دارد؛ - اگر
limit < 0‒ همه در متن مطابقت دارند - اگر
limit = 0‒ همه موارد در متن مطابقت داشته باشد، رشته های خالی در انتهای آرایه کنار گذاشته می شوند.
مثلا:
public static void main(String[] args) { String text = "Fred Anna Alexa"; Pattern pattern = Pattern.compile("\\s"); String[] strings = pattern.split(text,2); for (String s : strings) { System.out.println(s); } System.out.println("---------"); String[] strings1 = pattern.split(text); for (String s : strings1) { System.out.println(s); } }خروجی کنسول:
Fred Anna Alexa --------- Fred Anna Alexaدر زیر یکی دیگر از متدهای کلاس مورد استفاده برای ایجاد یک
Matcherشی را در نظر خواهیم گرفت. - اگر
روش های کلاس Matcher
نمونه هایی ازMatcherکلاس برای انجام تطبیق الگو ایجاد می شوند. Matcher"موتور جستجو" برای عبارات منظم است. برای انجام یک جستجو، باید دو چیز به آن بدهیم: یک الگو و یک شاخص شروع. برای ایجاد یک Matcherشی، Patternکلاس متد زیر را ارائه می دهد: рublic Matcher matcher(CharSequence input) متد یک دنباله کاراکتر می گیرد که جستجو می شود. این نمونه ای از کلاسی است که اینترفیس را پیاده سازی می کند CharSequence. شما می توانید نه تنها یک String، بلکه یک StringBuffer،،،، یا را StringBuilderپاس کنید . الگو شیئی است که متد بر روی آن فراخوانی می شود. نمونه ای از ایجاد تطبیق: SegmentCharBufferPatternmatcher
Pattern p = Pattern.compile("a*b"); // Create a compiled representation of the regular expression
Matcher m = p.matcher("aaaaab"); // Create a "search engine" to search the text "aaaaab" for the pattern "a*b" اکنون می توانیم از "موتور جستجو" خود برای جستجوی موارد منطبق استفاده کنیم، موقعیت یک مطابقت را در متن بدست آوریم و با استفاده از متدهای کلاس، متن را جایگزین کنیم. این boolean find()روش به دنبال مطابقت بعدی در متن است. ما می توانیم از این روش و یک دستور حلقه برای تجزیه و تحلیل کل متن به عنوان بخشی از یک مدل رویداد استفاده کنیم. به عبارت دیگر، زمانی که یک رویداد رخ می دهد، یعنی زمانی که یک مطابقت در متن پیدا می کنیم، می توانیم عملیات لازم را انجام دهیم. به عنوان مثال، ما می توانیم از این کلاس int start()و int end()متدها برای تعیین موقعیت یک مطابقت در متن استفاده کنیم. و می توانیم از متدهای String replaceFirst(String replacement)و String replaceAll(String replacement)برای جایگزینی مطابقت ها با مقدار پارامتر جایگزینی استفاده کنیم. مثلا:
public static void main(String[] args) {
String text = "Fred Anna Alexa";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found: " + text.substring(start, end) + " from index "+ start + " through " + (end-1));
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Mary"));
System.out.println(text);
} خروجی:
Match found: Anna from index 5 through 8
Match found: Alexa from index 10 through 14
Fred Ira Alexa
Fred Mary Mary
Fred Anna Alexa مثال روشن می کند که متدهای replaceFirstو replaceAllیک Stringشی جدید ایجاد می کنند - رشته ای که در آن الگوهای منطبق در متن اصلی با متن ارسال شده به متد به عنوان آرگومان جایگزین می شوند. علاوه بر این، replaceFirstمتد فقط اولین تطابق را جایگزین میکند، اما replaceAllروش جایگزین همه موارد مطابق در متن میشود. متن اصلی بدون تغییر باقی مانده است. متداولترین عملیات regex کلاسها مستقیماً در Patternکلاس ساخته میشوند . اینها روشهایی مانند , , , و . اما در زیر هود، این روش ها از کلاس های and استفاده می کنند . بنابراین اگر می خواهید بدون نوشتن کد اضافی، متن را جایگزین متن یا مقایسه رشته ها در برنامه کنید، از متدهای کلاس استفاده کنید . اگر به ویژگی های پیشرفته تری نیاز دارید، کلاس ها و را به خاطر بسپارید . MatcherStringsplitmatchesreplaceFirstreplaceAllPatternMatcherStringPatternMatcher
نتیجه
در یک برنامه جاوا، یک عبارت منظم توسط رشته ای تعریف می شود که از قوانین تطبیق الگوی خاصی پیروی می کند. هنگام اجرای کد، ماشین جاوا این رشته را در یکPatternشی کامپایل می کند و از یک Matcherشی برای یافتن مطابقت در متن استفاده می کند. همانطور که در ابتدا گفتم، مردم اغلب عبارات منظم را برای بعد موکول می کنند و آنها را موضوعی دشوار می دانند. اما اگر نحو اولیه، متاکاراکترها و فرار کاراکترها را درک کنید و نمونههایی از عبارات منظم را مطالعه کنید، متوجه خواهید شد که آنها بسیار سادهتر از آن چیزی هستند که در نگاه اول به نظر میرسند.
|
ادامه مطلب: |
|---|







GO TO FULL VERSION