×

Java Boyer Moore

A string searching or matching technique called the Boyer-Moore algorithm was created in 1977 by Robert S. Boyer and J. Strother Moore. It is the most popular and effective string-matching algorithm. Compared to the brute-force algorithm, it is substantially faster. The Boyer-Moore algorithm, its features, and its application in a Java program will all be covered in this article. It has a temporal complexity of O(nm+s). In most applications, the Boyer-Moore algorithm is the most efficient string-matching algorithm. In text editors, the «search» and «substitute» commands frequently use a simplified version of the algorithm or the entire algorithm.

Worst-case scenario

T=ssssssss……sssssss………ssssssss

P=psssssssss

The above sequence can be found in images and DNA sequences.

Characteristics of the Boyer Moore Algorithm

  • From right to left, it compares each character;
  • O(m+) time and space complexity characterize the pre-processing stage.
  • The searching step has an O(mn) complexity.
  • In the worst scenario, it compares 3n text characters when looking for a non-periodic pattern.
  • The complexity with the best performance is O(n/m).

The algorithm is based on the two heuristics listed below:

  • Character-Jump Heuristics
  • Looking-Glass Heuristics

Let's examine how the Boyer-Moore algorithm works.

The Boyer-Moore algorithm's operation

The method begins tracing characters from the pattern's rightmost character and advances leftward. It employs two pre-computed functions that shift the characters to the right and left, respectively, in the event of any mismatch and complete pattern matching. The good-suffix shift (also known as the matching shift) and the bad-character shift (or occurrence shift) are the names of these two pre-computed shift functions.

Note: Characters should be compared in a right-to-left sequence and aligned left to right to match the pattern.

Bad Character Shift

Skip alignment when there is a mismatch up until one of the following situations does not exist:

  1. Mismatch turns into a match
  2. P avoids mismatching characters

Take the text (T) and pattern (P) shown below as examples.

Boyer Moore Java

Start comparing the pattern now.

Step 1: First, align characters from left to right and compare them from right to left.

We can see that the last three characters of P correspond to those in T. T, the fourth character, is mismatched. As per the above guideline, skip alignment until a mismatch becomes a match. The seventh character (C) in P matched with C in T.

Boyer Moore Java

The above-displayed image shows the partial match.

Step 2: Move three characters to the right to match the pattern.

Compare the characters once more, this time from right to left, after moving. It matches the first character. We see that the character A is absent from the position to the left of P. P then shifts to the past mismatch character (A) in T in this instance.

Boyer Moore Java

The above-displayed image shows the procedure through which P and T attain matches.

Step 3: If P is moved past the mismatched character, we get,

Boyer Moore Java

From the above-displayed image, the pattern is matched. The sequence “CCTTTTGC” matches in both the T and P.

Note: The bad-character shift may not be good. Given that the Boyer-Moore method applies the maximum (skip characters) between the good-suffix shift and bad-character shift, it is appropriate to shift characters in this manner.

Good-Suffix Shift

Let's say that an inner loop matches the substring t. If so, skip characters up until:

  1. No mismatches exist between P and t.
  2. P moves past t.

Consider the following pattern as an example.

Boyer Moore Java

Step 1: Go from right to left and compare the characters. We can see that the last three characters of P correspond to characters in T denoted by t.

Boyer Moore Java

The above-displayed image shows the partial match.

Step 2: Continue until there is no match between P and t. The first four characters (from left to right) of P (C T T A C) correspond to the last five characters in t.

Boyer Moore Java

The above-displayed image shows the procedure through which P and t attain no matches.

Step 3: To get the match, skip three alignments. As a result, we get the match.

Boyer Moore Java

The above-displayed image shows the match. The sequence “CTTACTTAC” matches in both the T and P.

The two-shift functions described above can be defined as follows:

The good-suffix shift function is stored in a table of size m+1 called “bmGs”. The table “bmGs” is computed using a table “suff” defined as follows:

for 1 ? i < m, suff[i]=max{k : x[i-k+1 .. i]=x[m-k .. m-1]} 

The bad-character shift function is stored in a table bmBc of size s. For c in ∑:

bmBc[c] = min{i : 1 ? i <m-1 and x[m-1-i]=c} if c occurs in x, m otherwise. 

Pattern Matching Example Using Boyer Moore

Think about the following pattern.

Boyer Moore Java

Let's begin matching.

Step 1: Characters should be compared from right to left. The first character is mismatched, as G does not match with T.

Boyer Moore Java

Step 2: Skip the following few characters until we find a match. After six characters, a match is made. The good suffix shift rule will not be applicable in this case.

Boyer Moore Java

P moves past mismatch character (i.e. G), according to bad character shift.

Boyer Moore Java

Step 3: Compare characters once more from right to left. We can observe that P's first three characters match (t) with T, but its fourth character does not.

Boyer Moore Java

Both the bad and good character suffix can be used in this situation. When the bad character suffix is used, only one character is skipped. The good character suffix ignores two alignments when used. Therefore, since the algorithm says to skip additional alignments, we will use the good character suffix. Consequently, we omit two alignments.

Boyer Moore Java

Three characters of alignment are changed, and the result is:

Boyer Moore Java

Here, we can see that C is missing from P's area to the left. Good character alignments skip seven alignments, while bad character alignments skip two alignments.

Step 4: We can observe that the string is matched after changing a few characters.

Boyer Moore Java

We skipped 15 alignments in the earlier pattern, and 11 T characters were ignored.

Boyer Moore Pre-processing Phases

The following definition applies to calculated skips for the patterns T: A A T C A A T A G C and P: T C G C. The bad character shift function was employed in the above pattern.

Boyer Moore Java

The above table (characters) shows the number of skip alignments.

Pseudo Code for the Boyer Moore Algorithm

BoyerMooreMatch(H, T, ?)  
K<- lastOccurenceFunction(T, ?)  
i <- m-1  
j <- m-1  
repeat  
                    if H[i]=T[j]  
                             if j=0  
                                  return i {match at i}  
                             else  
                                  i <- i-1  
                                  j <- j-1  
                    else  
                         {character-jump}  
                         K<-K[H[i]]  
                         i <- i +m -min(j, 1+ l)  
                         j <- m-1  
until i>n-1  
return-1 {no match}  

Java Program for Pattern Searching

Let's look at the pattern-finding Java program. The brute-force string searching algorithm is implemented in the following program.

File name: PatternSearchingExample.java

import java.util.HashMap;  
import java.util.Map;  
public class PatternSearchingExample  
{  
/**  
* @example text -- trace the text to see if it contains pattern 
* @example pattern -- look for this text inside the text parameter 
* @return -- return index of the first match or -1 if not found 
*/  
public static int findBruteForce(char[] text, char[] pattern)   
{  
System.out.println("Brute force looking for " + String.valueOf(pattern) + " in " + String.valueOf(text)) ;  
int n = text.length ;  
int m = pattern.length ;  
//checks if the string is empty  
if (m == 0) return 0 ;  
//brute force it -- loop over all characters in text O(n)  
for (int i=0;i<=n-m;i++)   
{ //index into the text  
//loop over all characters in pattern while characters match O(m)  
//index into the pattern  
int k = 0 ;   
while (k<m && text[i+k] == pattern[k])   
{  
k++ ;  
}  
//if at the end of the pattern, then found match starting at index i in text  
if (k==m)   
{  
System.out.println("\tFound match in the given text at index " + i) ;  
return i ;  
}  
}  
//if a match is not found  
System.out.println("\tNo match found in the given text.") ;  
return -1 ;  
}  
/** 
 
* @example text -- search this text to see if it contains pattern 
* @example pattern -- look for this text inside the text parameter 
* @return -- return index of the first match or -1 if not found 
*/  
public static int findBoyerMoore(char[] text, char[] pattern)   
{  
System.out.println("Boyer-Moore looking for " + String.valueOf(pattern) + " in " + String.valueOf(text)) ;  //valueOf method is used
int n = text.length ;  // n stores length of the text
int m = pattern.length ;  
// Test for empty string  
if (m == 0) return 0 ;  
// Initialization, create Map of last position of each character = O(n)  
Map<Character, Integer> last = new HashMap<>() ;  //Map
for (int i = 0; i < n; i++)   
{  
// set all chars, by default, to -1      
last.put(text[i], -1) ;     
}          
for (int i = 0; i < m; i++)   
{  
// update last seen positions      
last.put(pattern[i], i) ;   
}  
//Start with the end of the pattern aligned at index m-1 in the text.   
//index into the text  
int i = m - 1 ;    
// index into the pattern  
int k = m - 1 ;    
while (i < n)   
{   
if (text[i] == pattern[k])   
{  
// match! return i if complete match; otherwise, keep checking      
if (k == 0)   
{  
System.out.println("\tFound match in the given text at index " + i) ;  
return i ;   
}  
i = i - 1 ; 
k--;   
}   
else   
{ // jump step + restart at end of pattern  
//iterate over the text   
i += m - Math.min(k, 1 + last.get(text[i])) ;    
//move to the end of the pattern  
k = m - 1 ;   
}  
}  
System.out.println("\tNo match found in the given text.") ;  
// prints as not found  
return -1 ;   
}  
public static void main(String args[])   
{  
char[] text = "abcfefabddef".toCharArray() ;  //string to character array
char[] pattern = "abddef".toCharArray() ;  //string to character array
//function calling  
findBruteForce(text,pattern) ;  //calls the findBruteForce function
findBoyerMoore(text,pattern) ;          //calls the findBruteForce function
}  
}   

Output

Boyer Moore Java

The above-displayed image is the output for the above program, and The output says that "abddef” is present in the “abcfefabddef” at index 6.

Let's use a Java program to implement the algorithm.

The Boyer Moore Java Program

Let's use a Java program to implement the Boyer-Moore algorithm and search pattern.

Program 1

Filename: BoyerMooreImplementation.java

public class BoyerMooreImplementation  
{  
static int NO_OF_CHARS = 256;   
static int max (int a, int b)   
{   
return (a > b)? a: b;   
}   
static void badCharHeuristic( char []str, int size, int badchar[])   
{   
int i;   
for (i = 0; i < NO_OF_CHARS; i++)   
badchar[i] = -1;   
for (i = 0; i < size; i++)   
badchar[(int) str[i]] = i;   
}   
static void search( char txt[],  char pat[])   
{   
int m = pat.length;   
int n = txt.length;   
int badchar[] = new int[NO_OF_CHARS];   
//function calling  
badCharHeuristic(pat, m, badchar);   
int s = 0;    
while(s <= (n - m))   
{   
int j = m-1;   
while(j >= 0 && pat[j] == txt[s+j])   
j--;   
if (j < 0)   
{   
System.out.println("Patterns occur at character = " + s);   
s += (s+m < n)? m-badchar[txt[s+m]] : 1;   
}   
else  
s += max(1, j - badchar[txt[s+j]]);   
}   
}   
public static void main(String args[])   
{   
//text in which pattern occurs  
char txt[] = "123651266512".toCharArray();   
//pattern to search  
char pat[] = "12".toCharArray();   
search(txt, pat);   
}   
}  

Output

Boyer Moore Java

Let's look at another Java program where we have distinct logic for pattern finding implemented. The code that follows next determines whether the text contains the required pattern.

Program 2

Filename: BoyerMooreExample.java

public class BoyerMooreExample  
{  
public static void main(String args[])   
{  
        System.out.println("Matching Pattern");  
        test("aabbccdef", "cde", 0);  
        test("zzzzaaapppxyzabc", "pqrs", 1);  
        test("mango", "ngo", 2);  
        test("abc", "d", -1);  
        test("catdog", "tdo", 2);  
        test("pqrsabcdxyzamnop", "cdxyza", 1);  
        test("cool", "", 0);  
        test("", "car", -1);  
}  
    public static void test(String text, String word, int exp)   
    {  
        char[] textC = text.toCharArray();  
        char[] wordC = word.toCharArray();  
        int result = bm(textC, wordC);  
        if(result == exp)  
            System.out.println("Pattern Matched");  
        else   
        {  
            System.out.println("Pattern Not Matched");  
            System.out.println("\ttext: " + text);  
            System.out.println("\tword: " + word);  
            System.out.println("\texp: " + exp + ", res: " + result);  
        }//end of else  
    }//end of function  
    public static int[] makeD1(char[] pat)   
    {  
        int[] table = new int[255];  
        for(int i=0; i<255; i++)  
            table[i] = pat.length;  
        for(int i=0; i<pat.length-1; i++)  
            table[pat[i]] = pat.length-1-i;  
        return table;  
    }//end of the function  
    public static boolean isPrefix(char[] word, int pos)   
    {  
        int suffixlen = word.length - pos;  
        for(int i=0; i<suffixlen; i++)  
            if(word[i] != word[pos+i])  
                return false;  
        return true;  
    }//end of the function  
    public static int suffix_length(char[] word, int pos)   
    {  
        int i;  
        for(i=0; ((word[pos-i] == word[word.length-1-i]) & (i < pos)); i++)  
            {  
                  
            }//end of for loop  
        return i;  
    }//end of the function   
    public static int[] makeD2(char[] pat)   
    {  
        int[] delta2 = new int[pat.length];  
        int p;  
        int last_prefix_index = pat.length - 1;  
        for(p = pat.length-1; p>=0; p--)   
        {  
            if(isPrefix(pat, p+1))  
                last_prefix_index = p+1;  
            delta2[p] = last_prefix_index + (pat.length-1-p);  
        }//end of for loop  
        for(p=0; p<pat.length-1; p++)   
        {  
            int slen = suffix_length(pat, p);  
            if(pat[p-slen] != pat[pat.length-1-slen])  
                delta2[pat.length-1-slen] = pat.length-1-p+slen;  
        }//end of for loop  
        return delta2;  
    }//end of function  
    public static int bm(char[] string, char[] pat)   
    {  
        int[] d1 = makeD1(pat);  
        int[] d2 = makeD2(pat);  
        int i = pat.length-1;  
        while(i < string.length)   
        {  
            int j = pat.length-1;  
            while(j>=0 && (string[i] == pat[j]))   
            {  
                i--; //decrement i by 1  
                j--; //decrement j by 1  
            }//end of while  
            if(j < 0)  
                return (i+1);  
            i += Math.max(d1[string[i]], d2[j]);  
        } //end of while  
        return -1;  
    }//end of the function  
}  

Output

Boyer Moore Java

Related Topics

Java Math expm1() Method

The expm1() method of Math class returns ex-1 where e represents Euler’s number. Syntax: public static double expm1(double x) Parameters: The parameter ‘x’ represents the exponent to raise e in the calculation of ex-1. Return...

2 minutes read.

Leap Year Program in Java

Leap Year Program in Java: A leap year is a calendar year that have an extra day i.e. 366 days instead of 365 days is called leap year. In other...

2 minutes read.

Java Math toDegrees() Method

The toDegrees() method of Java Math class converts a radian angle to an approximately equivalent angle measured in degrees. Syntax: public static double toDegrees(double angrad) Parameters: The parameter ‘angrad ‘represents an angle measured in...

2 minutes read.

Java Map Example

In Java, the Map is an interface that is used mainly to denote key and value pairs. The central concept and theme of this mapping in the java collection framework...

4 minutes read.

Java this keyword

This Keyword in Java This keyword can be used in many different ways in Java. This is a reference variable in Java that points to the active object. In Java, the...

8 minutes read.

Java 8 Features

Java 8 Features: After the great success of Java 7, many developers were waiting for the next version of one of the best languages in the tech world. Moreover, on...

6 minutes read.

How to compare dates in Java

Introduction: In Java, dates can be compared using a similar interface's compareTo() technique. This method returns 'zero' if each date is the same, returns a rate "more than 0" if...

6 minutes read.

Applet Life Cycle in Java

In this article, we are going to acknowledge you about what a applet is, what is its life cycle and stages in life cycle, along with the syntax and example...

4 minutes read.

Different Ways to Print Exception Message in Java

In this section, we will learn how to use various Java Throwable class methods to print exception messages. The Throwable class has the three methods listed below for printing the...

4 minutes read.

Java Integer toHexString() method

The toHexString() method of Java Integer class returns a string representing the specified int argument as an unsigned integer in base 16. Syntax public static String toHexString (int  i)  Parameters The parameter ‘i’ represents...

1 minute read.

History and Evolution of Java

Java is invented by James Gosling, Patrick Naughton, Chris Warth, Ed Frank, and Mike Sheridan at Sun Microsystems, Inc. in 1991. Java is related to C++, which is inherited from...

3 minutes read.

Java Primitive Data Types

Primitive data types are the simplest data types in a programming language. They’re predefined in the language. The names of the primitive types are quite descriptive of the values that...

2 minutes read.

Java Comparator Interface

Java comparator interface is used in a situation when we have to sort an object which does not implement Comparable or do sorting in a different way than the Comparable....

1 minute read.

Java For Keyword

For as a keyword in java: When we need to run a set of statements repeatedly in Java, we use loops. The Java for loop offers a clear way to express...

4 minutes read.

Use Of Adapter class in Java

An adapter class in Java enables listener interfaces to be implemented by default. The Delegation Event Model is where the idea of listener interfaces first appeared. It is one of...

3 minutes read.

Java Command not found

Java Command not found error is displayed if Java is not installed on the computer or if the command prompt cannot find Java.exe to run the program. Our Java software...

3 minutes read.

Java Enum Keyword

Definition: A data type in Java called Enum has a respect to supply of constants. The weekdays (SUN, MON, TUE, WED, THU, FRI, and SAT), directions (NORTH, SOUTH, EAST, and WEST),...

4 minutes read.

Generics in Java

Generics in Java Parameterizedtypes mean generic. Generics allow types (Character, Integer, String, …, etc., as well as user-defined types) to act as parameters to interfaces, classes, and methods. Generics in Java...

9 minutes read.

Java FileOutputStream

What is FileOutputStream?When we need raw stream data written into a file, we need to look for another option: FileOutputStream. It is used when the file's data is byte-oriented. It comes under...

4 minutes read.

Java Long Keyword

Long is a primitive data type in Java. To initilize variables, we implement the long keyword. It can also be applied to techniques. A 64-bit two's complement integer can put...

3 minutes read.