الگوریتم بویر مور برای جستجوی الگو — راهنمای کاربردی
«جستجوی الگو» (Pattern Searching) یک مسئله مهم در علوم کامپیوتر است. هنگامی که فرد به دنبال یک رشته در یک فایل مربوط به ویرایشگرهای متن (نوتپد، ورد، لیبرهآفیس و دیگر موارد)، مرورگر وب و یا «پایگاه داده» (Database) میگردد، الگوریتمهای جستجوی الگو برای نمایش نتایج جستجو مورد استفاده قرار میگیرند. یک بیان متداول از مسئله این است که متن txt[0..n-1] و الگوی pat[0..m-1] داده شده است. هدف نوشتن تابع search(char pat[], char txt[]) است که همه وقوعهای pat[] در txt[] را چاپ میکند. میتوان فرض کرد که n > m است.
مثالها:
Input: txt[] = "THIS IS A TEST TEXT" pat[] = "TEST" Output: Pattern found at index 10 Input: txt[] = "AABAACAADAABAABA" pat[] = "AABA" Output: Pattern found at index 0 Pattern found at index 9 Pattern found at index 12
در این مطلب، «الگوریتم جستجوی الگوی بویر مور» (Boyer Moore Pattern Searching Algorithm) مورد بررسی قرار خواهد کرد. همچون الگوریتمهای KMS و «اتوماتای متنهای» (Finite Automata)، الگوریتم بویر مور نیز الگو را «پیشپرداز» (Preprocesses) میکند. بویر مور، ترکیبی از دو رویکرد زیر است:
- هیوریستیک کاراکتر بد
- هیوریستیک پسوند خوب
هر دو «هیوریستیک» (Heuristic) بالا را میتوان به طور مستقل برای جستجوی یک الگو در متن استفاده کرد. اکنون، ابتدا چگونگی آنکه دو رویکرد مستقل در الگوریتم بویر مور با یکدیگر کار کنند مورد بررسی قرار میگیرد. با نگاهی به الگوریتم «بیز ساده» (Naive Algorithm)، میتوان فهمید که این الگوریتم الگو را با اسلاید کردن متن به صورت یک به یک انجام میدهد. الگوریتم KMP روی الگو پیشپردازش انجام میدهد
الگوریتم بویر مور پیشپردازش را به دلایل مشابهی با KMP انجام میدهد. این الگوریتم، الگو را پیشپردازش میکند و آرایههای متفاوتی را برای هر دو هیوریستیکها میسازد. در هر گام، این الگوریتم الگو را با حداکثر تعداد اسلایدهای پیشنهاد شده به وسیله دو هیوریستیک، اسلاید میکند. بنابراین، الگوریتم بویر مور در هر مرحله، بهترین هیوریستیک را از میان دو هیوریستیک موجود، استفاده میکند. در هر گام، این الگوریتم الگو را با بیشینه اسلایدهای پیشنهاد شده به وسیله دو هیوریستیک، اسلاید میکند. بنابراین، این الگوریتم از بهترین دو هیوریستیک موجود در هر گام استفاده میکند. برخلاف الگوی جستجوی پیشین، الگوریتم بویر مور تطبیق دادن را از آخرین کاراکتر الگو آغاز میکند. در این مطلب، هیوریستیک کاراکتر بد مورد بررسی قرار میگیرد.
هیوریستیک کاراکتر بد در الگوریتم بویر مور
ایده هیوریستیک کاراکتر بد، ساده است. کاراکتری از متن که با کاراکتر کنونی الگو مطابقت ندارد، «کاراکتر بد» (Bad Character) نامیده میشود. پس از عدم تطابق، الگو تا هنگامی جا به جا میشود که:
- عدم تطابق به یک تطابق مبدل شود.
- الگوی P کاراکتر تطبیق نیافته پیشین را حرکت دهد.
حالت ۱: عدم تطابق به تطابق مبدل میشود
موقعیت آخرین وقوع کاراکتر دارای عدم تطابق در الگو جستجو میشود و اگر کاراکتر دارای عدم تطابق در الگو وجود داشته باشد، الگو به گونهای جابهجا میشود که با کاراکتر دارای عدم تطابق در متن T، تراز شود.
توصیف: در مثال بالا، یک عدم تطابق در موقعیت ۳ به وقوع میپیوندد. در اینجا، کاراکتر تطبیق نیافته «A» است. اکنون، جستجو برای آخرین وقوع A انجام میشود. اکنون، الگو ۲ بار شیفت داده میشود بنابراین، «A» در الگو با A در متن تراز میشود.
حالت ۲: الگو کاراکتر ناسازگار را پشت سر میگذارد
موقعیت آخرین وقوع کاراکتر دارای عدم تطابق در الگو جستجو میشود و اگر کاراکتر وجود نداشت، الگو آخرین کاراکتر دارای عدم تطابق را پشت سر میگذارد.
توصیف مثال موجود در تصویر: در اینجا، یک عدم تطابق در موقعیت ۷ وجود دارد. کاراکتر دارای عدم تطابق «C» در الگو پیش از موقعیت ۷ وجود ندارد، بنابراین، الگو به پس از موقعیت ۷ جابهجا میشود و در نهایت در مثال بالا، تطابق خوبی از الگو (به رنگ سبز نمایش داده شده است) ایجاد میشود. این کار بدین دلیل انجام میشود که «C» در الگو وجود ندارد؛ بنابراین، در هر جا به جایی پیش از موقعیت ۷، عدم تطابق حاصل میشود و جستجو بیثمر خواهی بود.
در پیادهسازی که در ادامه آمده است، الگو پیشپردازش میشود و آخرین وقوع از هر کاراکتر ممکنی در آرایه با اندازه مشابه با اندازه الفبایی پیشپردازش میشود. اگر کاراکتر اصلا وجود نداشت، در نهایت ممکن است منجر به جا به جایی m (طول الگو) شود. بنابراین، هیوریستیک کاراکتر بد، به اندازه (O(n/m بار در بهترین حالت، زمان میبرد.
پیادهسازی الگوریتم بویر مور در ++C
/* C++ Program for Bad Character Heuristic of Boyer Moore String Matching Algorithm */ #include <bits/stdc++.h> using namespace std; # define NO_OF_CHARS 256 // The preprocessing function for Boyer Moore's // bad character heuristic void badCharHeuristic( string str, int size, int badchar[NO_OF_CHARS]) { int i; // Initialize all occurrences as -1 for (i = 0; i < NO_OF_CHARS; i++) badchar[i] = -1; // Fill the actual value of last occurrence // of a character for (i = 0; i < size; i++) badchar[(int) str[i]] = i; } /* A pattern searching function that uses Bad Character Heuristic of Boyer Moore Algorithm */ void search( string txt, string pat) { int m = pat.size(); int n = txt.size(); int badchar[NO_OF_CHARS]; /* Fill the bad character array by calling the preprocessing function badCharHeuristic() for given pattern */ badCharHeuristic(pat, m, badchar); int s = 0; // s is shift of the pattern with // respect to text while(s <= (n - m)) { int j = m - 1; /* Keep reducing index j of pattern while characters of pattern and text are matching at this shift s */ while(j >= 0 && pat[j] == txt[s + j]) j--; /* If the pattern is present at current shift, then index j will become -1 after the above loop */ if (j < 0) { cout << "pattern occurs at shift = " << s << endl; /* Shift the pattern so that the next character in text aligns with the last occurrence of it in pattern. The condition s+m < n is necessary for the case when pattern occurs at the end of text */ s += (s + m < n)? m-badchar[txt[s + m]] : 1; } else /* Shift the pattern so that the bad character in text aligns with the last occurrence of it in pattern. The max function is used to make sure that we get a positive shift. We may get a negative shift if the last occurrence of bad character in pattern is on the right side of the current character. */ s += max(1, j - badchar[txt[s + j]]); } } /* Driver code */ int main() { string txt= "ABAAABCD"; string pat = "ABC"; search(txt, pat); return 0; } // This code is contributed by rathbhupendra
پیادهسازی الگوریتم بویر مورد در سی
/* C Program for Bad Character Heuristic of Boyer Moore String Matching Algorithm */ # include <limits.h> # include <string.h> # include <stdio.h> # define NO_OF_CHARS 256 // A utility function to get maximum of two integers int max (int a, int b) { return (a > b)? a: b; } // The preprocessing function for Boyer Moore's // bad character heuristic void badCharHeuristic( char *str, int size, int badchar[NO_OF_CHARS]) { int i; // Initialize all occurrences as -1 for (i = 0; i < NO_OF_CHARS; i++) badchar[i] = -1; // Fill the actual value of last occurrence // of a character for (i = 0; i < size; i++) badchar[(int) str[i]] = i; } /* A pattern searching function that uses Bad Character Heuristic of Boyer Moore Algorithm */ void search( char *txt, char *pat) { int m = strlen(pat); int n = strlen(txt); int badchar[NO_OF_CHARS]; /* Fill the bad character array by calling the preprocessing function badCharHeuristic() for given pattern */ badCharHeuristic(pat, m, badchar); int s = 0; // s is shift of the pattern with // respect to text while(s <= (n - m)) { int j = m-1; /* Keep reducing index j of pattern while characters of pattern and text are matching at this shift s */ while(j >= 0 && pat[j] == txt[s+j]) j--; /* If the pattern is present at current shift, then index j will become -1 after the above loop */ if (j < 0) { printf("\n pattern occurs at shift = %d", s); /* Shift the pattern so that the next character in text aligns with the last occurrence of it in pattern. The condition s+m < n is necessary for the case when pattern occurs at the end of text */ s += (s+m < n)? m-badchar[txt[s+m]] : 1; } else /* Shift the pattern so that the bad character in text aligns with the last occurrence of it in pattern. The max function is used to make sure that we get a positive shift. We may get a negative shift if the last occurrence of bad character in pattern is on the right side of the current character. */ s += max(1, j - badchar[txt[s+j]]); } } /* Driver program to test above function */ int main() { char txt[] = "ABAAABCD"; char pat[] = "ABC"; search(txt, pat); return 0; }
پیادهسازی الگوریتم بویر مور در جاوا
/* Java Program for Bad Character Heuristic of Boyer Moore String Matching Algorithm */ class AWQ{ static int NO_OF_CHARS = 256; //A utility function to get maximum of two integers static int max (int a, int b) { return (a > b)? a: b; } //The preprocessing function for Boyer Moore's //bad character heuristic static void badCharHeuristic( char []str, int size,int badchar[]) { int i; // Initialize all occurrences as -1 for (i = 0; i < NO_OF_CHARS; i++) badchar[i] = -1; // Fill the actual value of last occurrence // of a character for (i = 0; i < size; i++) badchar[(int) str[i]] = i; } /* A pattern searching function that uses Bad Character Heuristic of Boyer Moore Algorithm */ static void search( char txt[], char pat[]) { int m = pat.length; int n = txt.length; int badchar[] = new int[NO_OF_CHARS]; /* Fill the bad character array by calling the preprocessing function badCharHeuristic() for given pattern */ badCharHeuristic(pat, m, badchar); int s = 0; // s is shift of the pattern with // respect to text while(s <= (n - m)) { int j = m-1; /* Keep reducing index j of pattern while characters of pattern and text are matching at this shift s */ while(j >= 0 && pat[j] == txt[s+j]) j--; /* If the pattern is present at current shift, then index j will become -1 after the above loop */ if (j < 0) { System.out.println("Patterns occur at shift = " + s); /* Shift the pattern so that the next character in text aligns with the last occurrence of it in pattern. The condition s+m < n is necessary for the case when pattern occurs at the end of text */ s += (s+m < n)? m-badchar[txt[s+m]] : 1; } else /* Shift the pattern so that the bad character in text aligns with the last occurrence of it in pattern. The max function is used to make sure that we get a positive shift. We may get a negative shift if the last occurrence of bad character in pattern is on the right side of the current character. */ s += max(1, j - badchar[txt[s+j]]); } } /* Driver program to test above function */ public static void main(String []args) { char txt[] = "ABAAABCD".toCharArray(); char pat[] = "ABC".toCharArray(); search(txt, pat); } }
پیادهسازی الگوریتم بویر مور در پایتون
# Python3 Program for Bad Character Heuristic # of Boyer Moore String Matching Algorithm NO_OF_CHARS = 256 def badCharHeuristic(string, size): ''' The preprocessing function for Boyer Moore's bad character heuristic ''' # Initialize all occurrence as -1 badChar = [-1]*NO_OF_CHARS # Fill the actual value of last occurrence for i in range(size): badChar[ord(string[i])] = i; # retun initialized list return badChar def search(txt, pat): ''' A pattern searching function that uses Bad Character Heuristic of Boyer Moore Algorithm ''' m = len(pat) n = len(txt) # create the bad character list by calling # the preprocessing function badCharHeuristic() # for given pattern badChar = badCharHeuristic(pat, m) # s is shift of the pattern with respect to text s = 0 while(s <= n-m): j = m-1 # Keep reducing index j of pattern while # characters of pattern and text are matching # at this shift s while j>=0 and pat[j] == txt[s+j]: j -= 1 # If the pattern is present at current shift, # then index j will become -1 after the above loop if j<0: print("Pattern occur at shift = {}".format(s)) ''' Shift the pattern so that the next character in text aligns with the last occurrence of it in pattern. The condition s+m < n is necessary for the case when pattern occurs at the end of text ''' s += (m-badChar[ord(txt[s+m])] if s+m<n else 1) else: ''' Shift the pattern so that the bad character in text aligns with the last occurrence of it in pattern. The max function is used to make sure that we get a positive shift. We may get a negative shift if the last occurrence of bad character in pattern is on the right side of the current character. ''' s += max(1, j-badChar[ord(txt[s+j])]) # Driver program to test above function def main(): txt = "ABAAABCD" pat = "ABC" search(txt, pat) if __name__ == '__main__': main() # This code is contributed by Atul Kumar # (www.facebook.com/atul.kr.007)
پیادهسازی الگوریتم بویر مور در #C
/* C# Program for Bad Character Heuristic of Boyer Moore String Matching Algorithm */ using System; public class AWQ{ static int NO_OF_CHARS = 256; //A utility function to get maximum of two integers static int max (int a, int b) { return (a > b)? a: b; } //The preprocessing function for Boyer Moore's //bad character heuristic static void badCharHeuristic( char []str, int size,int []badchar) { int i; // Initialize all occurrences as -1 for (i = 0; i < NO_OF_CHARS; i++) badchar[i] = -1; // Fill the actual value of last occurrence // of a character for (i = 0; i < size; i++) badchar[(int) str[i]] = i; } /* A pattern searching function that uses Bad Character Heuristic of Boyer Moore Algorithm */ static void search( char []txt, char []pat) { int m = pat.Length; int n = txt.Length; int []badchar = new int[NO_OF_CHARS]; /* Fill the bad character array by calling the preprocessing function badCharHeuristic() for given pattern */ badCharHeuristic(pat, m, badchar); int s = 0; // s is shift of the pattern with // respect to text while(s <= (n - m)) { int j = m-1; /* Keep reducing index j of pattern while characters of pattern and text are matching at this shift s */ while(j >= 0 && pat[j] == txt[s+j]) j--; /* If the pattern is present at current shift, then index j will become -1 after the above loop */ if (j < 0) { Console.WriteLine("Patterns occur at shift = " + s); /* Shift the pattern so that the next character in text aligns with the last occurrence of it in pattern. The condition s+m < n is necessary for the case when pattern occurs at the end of text */ s += (s+m < n)? m-badchar[txt[s+m]] : 1; } else /* Shift the pattern so that the bad character in text aligns with the last occurrence of it in pattern. The max function is used to make sure that we get a positive shift. We may get a negative shift if the last occurrence of bad character in pattern is on the right side of the current character. */ s += max(1, j - badchar[txt[s+j]]); } } /* Driver program to test above function */ public static void Main() { char []txt = "ABAAABCD".ToCharArray(); char []pat = "ABC".ToCharArray(); search(txt, pat); } } // This code is contributed by PrinciRaj19992
خروجی پیادهسازیهای بالا، به صورت زیر است.
pattern occurs at shift = 4
هیوریستیک کاراکتر بد ممکن است در بدترین حالت، از درجه (O(mn زمان ببرد. بدترین حالت هنگامی به وقوع میپیوندد که همه کاراکترهای متن و الگو مشابه باشند. برای مثال، ”txt[] = “AAAAAAAAAAAAAAAAAA و ”pat[] = “AAAAA را داشته باشیم.
اگر نوشته بالا برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامه نویسی
- آموزش ساختمان دادهها
- مجموعه آموزشهای ساختمان داده و طراحی الگوریتم
- رنگآمیزی گراف به روش حریصانه — به زبان ساده
- الگوریتم دایجسترا (Dijkstra) — از صفر تا صد
- الگوریتم پریم — به زبان ساده
- متن کاوی (Text Mining) — به زبان ساده
مجموعه: برنامه نویسی, تشخیص الگو برچسب ها: Pattern Recognition, Pattern Searching, الگوریتم بویر مور, الگوریتم بویر مور در #C, الگوریتم بویر مور در پایتون, الگوریتم بویر مور در جاوا, الگوریتم بویر مورد در ++C, بازشناسی الگو, برنامه نویسی الگوریتم بویر مور, تطبیق الگو, جستجوی الگو