<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>string searching algorithms &#8211; stoimen&#039;s web log</title>
	<atom:link href="/tag/string-searching-algorithms/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>on web development</description>
	<lastBuildDate>Tue, 13 Feb 2018 08:18:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.0.3</generator>
	<item>
		<title>Computer Algorithms: Boyer-Moore String Searching</title>
		<link>/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/</link>
		<comments>/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/#comments</comments>
		<pubDate>Tue, 17 Apr 2012 08:24:46 +0000</pubDate>
		<dc:creator><![CDATA[Stoimen]]></dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[Boyer–Moore string search algorithm]]></category>
		<category><![CDATA[Boyer–Moore–Horspool algorithm]]></category>
		<category><![CDATA[Computer programming]]></category>
		<category><![CDATA[Computer science]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[J Strother Moore]]></category>
		<category><![CDATA[Morris-Pratt algorithm]]></category>
		<category><![CDATA[natural language search]]></category>
		<category><![CDATA[pattern forward]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Rabin-Karp algorithm]]></category>
		<category><![CDATA[Rabin-Karp string search algorithm]]></category>
		<category><![CDATA[Robert S. Boyer]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[search algorithms]]></category>
		<category><![CDATA[String searching algorithm]]></category>
		<category><![CDATA[string searching algorithms]]></category>
		<category><![CDATA[Strlen]]></category>
		<category><![CDATA[Substring]]></category>

		<guid isPermaLink="false">/?p=3049</guid>
		<description><![CDATA[Introduction Have you ever asked yourself which is the algorithm used to find a word after clicking Ctrl+F and typing something? Well I guess you know the answer from the title, but in this article you’ll find out how exactly this is done. As we saw from the Morris-Pratt string searching we don’t need to &#8230; <a href="/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/" class="more-link">Continue reading <span class="screen-reader-text">Computer Algorithms: Boyer-Moore String Searching</span> <span class="meta-nav">&#8594;</span></a><div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href="/2012/04/09/computer-algorithms-morris-pratt-string-searching/" rel="bookmark" title="Computer Algorithms: Morris-Pratt String Searching">Computer Algorithms: Morris-Pratt String Searching </a></li>
<li><a href="/2012/04/02/computer-algorithms-rabin-karp-string-searching/" rel="bookmark" title="Computer Algorithms: Rabin-Karp String Searching">Computer Algorithms: Rabin-Karp String Searching </a></li>
<li><a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" rel="bookmark" title="Computer Algorithms: Brute Force String Matching">Computer Algorithms: Brute Force String Matching </a></li>
<li><a href="/2011/11/24/computer-algorithms-sequential-search/" rel="bookmark" title="Computer Algorithms: Sequential Search">Computer Algorithms: Sequential Search </a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p>Have you ever asked yourself which is the algorithm used to find a word after clicking Ctrl+F and typing something? Well I guess you know the answer from the title, but in this article you’ll find out how exactly this is done.</p>
<p>As we saw from the <a href="/2012/04/09/computer-algorithms-morris-pratt-string-searching/" title="Computer Algorithms: Morris-Pratt String Searching">Morris-Pratt string searching</a> we don’t need to compare the text and the pattern character by character. Some comparisons can be skipped in order to improve the performance of the string searching. Indeed the <a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" title="Computer Algorithms: Brute Force String Matching">brute force string searching</a> and the <a href="/2012/04/02/computer-algorithms-rabin-karp-string-searching/" title="Computer Algorithms: Rabin-Karp String Searching">Rabin-Karp algorithm</a> are quite slow only because they compare the pattern and the text character by character.</p>
<p>In the other hand the Morris-Pratt algorithm is a very good improvement of the brute force string searching, but the question remains. Is there any algorithm that is faster than Morris-Pratt &#8211; is there any way to skip more comparisons and to move the pattern faster.</p>
<p>It’s clear that if we have to find whether a single character is contained into a text we need at least &#8220;n&#8221; steps, where n is the length of the text. Once we have to find whether a pattern with the length of &#8220;m&#8221; is contained into a text with length of &#8220;n&#8221; the case is getting a little more complex.</p>
<p>However the answer is that there is such algorithm that is faster and more suitable than Morris-Pratt. This is the Boyer-Moore string searching.</p>
<h2>Overview</h2>
<p>Boyer-Moore is an algorithm that improves the performance of pattern searching into a text by considering some observations. It is defined in 1977 by <a href="http://en.wikipedia.org/wiki/Robert_S._Boyer" title="Robert S. Boyer" target="_blank">Robert S. Boyer</a> and <a href="http://en.wikipedia.org/wiki/J_Strother_Moore" title="J Strother Moore" target="_blank">J Strother Moore</a> and it consist of some specific features. </p>
<p>First of all this algorithm starts comparing the pattern from the leftmost part of text and moves it to the right, as on the picture below.</p>
<p><figure id="attachment_3059" style="width: 618px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreShiftingDirection.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreShiftingDirection.png" alt="Boyer-Moore Shifting Direction" title="Boyer-Moore Shifting Direction" width="618" height="153" class="size-full wp-image-3059" srcset="/wp-content/uploads/2012/04/Boyer-MooreShiftingDirection.png 618w, /wp-content/uploads/2012/04/Boyer-MooreShiftingDirection-300x74.png 300w" sizes="(max-width: 618px) 100vw, 618px" /></a><figcaption class="wp-caption-text">In Boyer-Moore the pattern is shifted from left to right!</figcaption></figure><span id="more-3049"></span></p>
<p>Unlike other string searching algorithms though, Boyer-Moore compares the pattern against a possible match from right to left as shown below.</p>
<figure id="attachment_3066" style="width: 622px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreComparisonModel.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreComparisonModel.png" alt="Boyer-Moore Comparison Model" title="Boyer-Moore Comparison Model" width="622" height="169" class="size-full wp-image-3066" srcset="/wp-content/uploads/2012/04/Boyer-MooreComparisonModel.png 622w, /wp-content/uploads/2012/04/Boyer-MooreComparisonModel-300x81.png 300w" sizes="(max-width: 622px) 100vw, 622px" /></a><figcaption class="wp-caption-text">Unlike other algorithms the letters of the pattern are compared from right to left!</figcaption></figure>
<p>The main idea of Boyer-Moore in order to improve the performance are some observations of the pattern. In the terminology of this algorithm they are called good-suffix and bad-character shifts. Let’s see by the following examples what they are standing for.</p>
<h3>Good-suffix Shifts</h3>
<p>Just like the Morris-Pratt algorithm we start to compare the pattern against some portion of the text where a possible match will occur. In Boyer-Moore as I said this is done from the rightmost letter of the pattern. After some characters have matched we find a mismatch.</p>
<figure id="attachment_3065" style="width: 622px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreAMismatch.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreAMismatch.png" alt="Boyer-Moore a Mismatch" title="Boyer-Moore a Mismatch" width="622" height="214" class="size-full wp-image-3065" srcset="/wp-content/uploads/2012/04/Boyer-MooreAMismatch.png 622w, /wp-content/uploads/2012/04/Boyer-MooreAMismatch-300x103.png 300w" sizes="(max-width: 622px) 100vw, 622px" /></a><figcaption class="wp-caption-text"> </figcaption></figure>
<p>So how can we move the pattern to the right in order to skip unusual comparisons. To answer this question we need to explore the pattern. Let’s say there is a portion of the pattern that is repeated inside the pattern itself, like it is shown on the picture below.</p>
<figure id="attachment_3062" style="width: 622px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreGood-suffixShift1.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreGood-suffixShift1.png" alt="Boyer-Moore Good-suffix Shift 1" title="Boyer-Moore Good-suffix Shift 1" width="622" height="195" class="size-full wp-image-3062" srcset="/wp-content/uploads/2012/04/Boyer-MooreGood-suffixShift1.png 622w, /wp-content/uploads/2012/04/Boyer-MooreGood-suffixShift1-300x94.png 300w" sizes="(max-width: 622px) 100vw, 622px" /></a><figcaption class="wp-caption-text">The pattern may consist of repeating portions of characters!</figcaption></figure>
<p>In this case we must move the pattern thus the repeated portion must now align with its first occurrence in the pattern.</p>
<p>A variation of this case is when the portion from the pattern A overlaps with another portion that consists of the same characters.</p>
<figure id="attachment_3061" style="width: 622px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift2.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift2.png" alt="Boyer-Moore Good Suffix Shift 2" title="Boyer-Moore Good Suffix Shift 2" width="622" height="195" class="size-full wp-image-3061" srcset="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift2.png 622w, /wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift2-300x94.png 300w" sizes="(max-width: 622px) 100vw, 622px" /></a><figcaption class="wp-caption-text">Sometimes these portions may overlap!</figcaption></figure>
<p>Yet again the shift must align the second portion with its first occurrence. </p>
<p>Finally only a portion of A, let’s say &#8220;B&#8221;, can happen to occur in the very beginning of the pattern, as on the diagram below.</p>
<figure id="attachment_3060" style="width: 622px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift3.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift3.png" alt="Boyer-Moore Good Suffix Shift 3" title="Boyer-Moore Good Suffix Shift 3" width="622" height="195" class="size-full wp-image-3060" srcset="/wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift3.png 622w, /wp-content/uploads/2012/04/Boyer-MooreGoodSuffixShift3-300x94.png 300w" sizes="(max-width: 622px) 100vw, 622px" /></a><figcaption class="wp-caption-text">Only a sub-string of the pattern may re-occur at its front!</figcaption></figure>
<p>Now we must align the left end of the pattern with the rightmost occurrence of &#8220;B&#8221;.</p>
<h3>Bad Character Shifts</h3>
<p>Beside the good-suffix shifts the Boyer-Moore algorithm make use of the so called bad-character shifts. In case of a mismatch we can skip comparisons in case the character in the text doesn’t happen to appear in the pattern. To become clearer let’s see the following examples.</p>
<figure id="attachment_3064" style="width: 623px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter1.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter1.png" alt="Boyer-Moore Bad Character 1" title="Boyer-Moore Bad Character 1" width="623" height="237" class="size-full wp-image-3064" srcset="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter1.png 623w, /wp-content/uploads/2012/04/Boyer-MooreBadCharacter1-300x114.png 300w" sizes="(max-width: 623px) 100vw, 623px" /></a><figcaption class="wp-caption-text">If the mismatched letter of the text appears in the pattern only in its front we can align it easily!</figcaption></figure>
<p>In the picture above we see that the mismatched character &#8220;B&#8221; from the text appears only in the beginning of the pattern. Thus we can simply shift the pattern to the right and align both characters B, skipping comparisons. An even better case is described by the following diagram where the mismatched letter isn’t contained into the pattern at all. Then we can shift forward the whole pattern.</p>
<figure id="attachment_3063" style="width: 623px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter2.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter2.png" alt="Boyer-Moore Bad Character 2" title="Boyer-Moore Bad Character 2" width="623" height="237" class="size-full wp-image-3063" srcset="/wp-content/uploads/2012/04/Boyer-MooreBadCharacter2.png 623w, /wp-content/uploads/2012/04/Boyer-MooreBadCharacter2-300x114.png 300w" sizes="(max-width: 623px) 100vw, 623px" /></a><figcaption class="wp-caption-text">In case the mismatched letter isn&#039;t contained into the pattern we move forward the pattern!</figcaption></figure>
<h3>Maximum of Good-suffix and Bad-Character shifts</h3>
<p>Boyer-Moore needs both good-suffix and bad-character shifts in order to speed up searching performance. After a mismatch the maximum of both is considered in order to move the pattern to the right.</p>
<h2>Complexity</h2>
<p>It&#8217;s clear that Boyer-Moore is faster than Morris-Pratt, but actually its worst-case complexity is O(n+m). The thing is that in natural language search Boyer-Moore does pretty well.</p>
<figure id="attachment_3073" style="width: 600px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-Moore-Complexity.png"><img src="/wp-content/uploads/2012/04/Boyer-Moore-Complexity.png" alt="Boyer-Moore Complexity" title="Boyer-Moore Complexity" width="600" height="371" class="size-full wp-image-3073" srcset="/wp-content/uploads/2012/04/Boyer-Moore-Complexity.png 600w, /wp-content/uploads/2012/04/Boyer-Moore-Complexity-300x185.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><figcaption class="wp-caption-text">Worst-case scenario of Boyer-Moore - O(m+n)</figcaption></figure>
<h2>Implementation</h2>
<p>Finally let’s see the implementation in <a href="/category/php/" title="PHP on stoimen.com">PHP</a>, which can be easily &#8220;transcribed&#8221; into any other programming language. The only thing we need is the structures for bad-character shifts and good-suffixes shifts.</p>
<pre lang="PHP">
<?php

/**
 * Pattern we're searching for
 *
 * @var string
 */
$pattern = 'gloria';

/**
 * The text we're searching in
 *
 * @var string
 */
$text = 'Sic transit gloria mundi, non transit gloria Gundi!';

/**
 * Calculates the suffixes for a given pattern
 *
 * @param string $pattern
 * @param array  $suffixes
 */
function suffixes($pattern, &#038;$suffixes)
{
   $m = strlen($pattern);

   $suffixes[$m - 1] = $m;
   $g = $m - 1;

   for ($i = $m - 2; $i >= 0; --$i) {
      if ($i > $g && $suffixes[$i + $m - 1 - $f] < $i - $g) {
         $suffixes[$i] = $suffixes[$i + $m - 1 - $f];
      } else {
         if ($i < $g) {
            $g = $i;
         }
         $f = $i;
         	
         while ($g >= 0 && $pattern[$g] == $pattern[$g + $m - 1 - $f]) {
            $g--;
         }
         $suffixes[$i] = $f - $g;
      }
   }
}

/**
 * Fills in the array of bad characters.
 *
 * @param string $pattern
 * @param array  $badChars
 */
function badCharacters($pattern, &$badChars)
{
   $m = strlen($pattern);

   for ($i = 0; $i < $m - 1; ++$i) {
      $badChars[$pattern{$i}] = $m - $i - 1;
   }
}

/**
 * Fills in the array of good suffixes
 *
 * @param string $pattern
 * @param array  $goodSuffixes
 */
function goodSuffixes($pattern, &#038;$goodSuffixes)
{
   $m 		= strlen($pattern);
   $suff 	= array();

   suffixes($pattern, $suff);

   for ($i = 0; $i < $m; $i++) {
      $goodSuffixes[$i] = $m;
   }

   for ($i = $m - 1; $i >= 0; $i--) {
      if ($suff[$i] == $i + 1) {
         for ($j = 0; $j < $m - $i - 1; $j++) {
            if ($goodSuffixes[$j] == $m) {
               $goodSuffixes[$j] = $m - $i - 1;
            }
         }
      }
   }

   for ($i = 0; $i < $m - 2; $i++) {
      $goodSuffixes[$m - 1 - $suff[$i]] = $m - $i - 1;
   }
}

/**
 * Performs a search of the pattern into a given text
 *
 * @param string $pattern
 * @param string $text
 */
function boyer_moore($pattern, $text)
{
   $n = strlen($text);
   $m = strlen($pattern);

   $goodSuffixes 	= array();
   $badCharacters 	= array();

   goodSuffixes($pattern, &#038;$goodSuffixes);
   badCharacters($pattern, &#038;$badCharacters);

   $j = 0;
   while ($j < $n - $m) {
      for ($i = $m - 1; $i >= 0 && $pattern[$i] == $text[$i + $j]; $i--);
      if ($i < 0) {
         // note that if the substring occurs more
         // than once into the text, the algorithm will
         // print out each position of the substring
         echo $j;
         $j += $goodSuffixes[0];
      } else {
         $j += max($goodSuffixes[$i], $badCharacters[$text[$i + $j]] - $m + $i + 1);
      }
   }
}

// search using Boyer-Moore
// will return 12 and 38
boyer_moore($pattern, $text);
</pre>
<h2>Application</h2>
<p>Boyer-Moore is one of the most used string searching algorithm in practice. It is intuitively clear where it can be useful, but yet again I’ll say only that this algorithm is considered as the mostly used in practice for search and replace operations in text editors.</p>
<figure id="attachment_3068" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Boyer-MooreApplication.png"><img src="/wp-content/uploads/2012/04/Boyer-MooreApplication.png" alt="Boyer-Moore Application" title="Boyer-Moore Application" width="620" height="399" class="size-full wp-image-3068" srcset="/wp-content/uploads/2012/04/Boyer-MooreApplication.png 620w, /wp-content/uploads/2012/04/Boyer-MooreApplication-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text"> </figcaption></figure>
<div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href="/2012/04/09/computer-algorithms-morris-pratt-string-searching/" rel="bookmark" title="Computer Algorithms: Morris-Pratt String Searching">Computer Algorithms: Morris-Pratt String Searching </a></li>
<li><a href="/2012/04/02/computer-algorithms-rabin-karp-string-searching/" rel="bookmark" title="Computer Algorithms: Rabin-Karp String Searching">Computer Algorithms: Rabin-Karp String Searching </a></li>
<li><a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" rel="bookmark" title="Computer Algorithms: Brute Force String Matching">Computer Algorithms: Brute Force String Matching </a></li>
<li><a href="/2011/11/24/computer-algorithms-sequential-search/" rel="bookmark" title="Computer Algorithms: Sequential Search">Computer Algorithms: Sequential Search </a></li>
</ol></p>
</div>
]]></content:encoded>
			<wfw:commentRss>/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Computer Algorithms: Rabin-Karp String Searching</title>
		<link>/2012/04/02/computer-algorithms-rabin-karp-string-searching/</link>
		<comments>/2012/04/02/computer-algorithms-rabin-karp-string-searching/#comments</comments>
		<pubDate>Mon, 02 Apr 2012 19:48:15 +0000</pubDate>
		<dc:creator><![CDATA[Stoimen]]></dc:creator>
				<category><![CDATA[algorithms]]></category>
		<category><![CDATA[ASCII]]></category>
		<category><![CDATA[basic sub-string matching algorithm]]></category>
		<category><![CDATA[Boyer–Moore string search algorithm]]></category>
		<category><![CDATA[Complexity The Rabin-Karp algorithm]]></category>
		<category><![CDATA[Cryptographic hash function]]></category>
		<category><![CDATA[Cryptography]]></category>
		<category><![CDATA[Hash function]]></category>
		<category><![CDATA[Hash table]]></category>
		<category><![CDATA[Hashing]]></category>
		<category><![CDATA[Michael O. Rabin]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Rabin-Karp algorithm]]></category>
		<category><![CDATA[Rabin-Karp string search algorithm]]></category>
		<category><![CDATA[Richard M. Karp]]></category>
		<category><![CDATA[Rolling hash]]></category>
		<category><![CDATA[search algorithms]]></category>
		<category><![CDATA[string matching algorithms]]></category>
		<category><![CDATA[String searching algorithm]]></category>
		<category><![CDATA[string searching algorithms]]></category>
		<category><![CDATA[sub-string matching algorithms]]></category>
		<category><![CDATA[This algorithm]]></category>

		<guid isPermaLink="false">/?p=2991</guid>
		<description><![CDATA[Introduction Brute force string matching is the a very basic sub-string matching algorithm, but it’s good for some reasons. For example it doesn’t require preprocessing of the text or the pattern. The problem is that it’s very slow. That is why in many cases brute force matching can’t be very useful. For pattern matching we &#8230; <a href="/2012/04/02/computer-algorithms-rabin-karp-string-searching/" class="more-link">Continue reading <span class="screen-reader-text">Computer Algorithms: Rabin-Karp String Searching</span> <span class="meta-nav">&#8594;</span></a><div class='yarpp-related-rss'>

Related posts:<ol>
<li><a href="/2012/04/09/computer-algorithms-morris-pratt-string-searching/" rel="bookmark" title="Computer Algorithms: Morris-Pratt String Searching">Computer Algorithms: Morris-Pratt String Searching </a></li>
<li><a href="/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/" rel="bookmark" title="Computer Algorithms: Boyer-Moore String Searching">Computer Algorithms: Boyer-Moore String Searching </a></li>
<li><a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" rel="bookmark" title="Computer Algorithms: Brute Force String Matching">Computer Algorithms: Brute Force String Matching </a></li>
<li><a href="/2011/08/18/powerful-php-less-known-string-manipulation/" rel="bookmark" title="Powerful PHP: Less Known String Manipulation">Powerful PHP: Less Known String Manipulation </a></li>
</ol>
</div>
]]></description>
				<content:encoded><![CDATA[<h2>Introduction</h2>
<p><a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" title="Computer Algorithms: Brute Force String Searching">Brute force string matching</a> is the a very basic sub-string matching algorithm, but it’s good for some reasons. For example it doesn’t require preprocessing of the text or the pattern. The problem is that it’s very slow. That is why in many cases brute force matching can’t be very useful. For pattern matching we need something faster, but to understand other sub-string matching algorithms let’s take a look once again on brute force matching. </p>
<p>In brute force sub-string matching we checked every single character from the text with the first character of the pattern. Once we have a match between them we shift the comparison between the second character of the pattern with the next character of the text, as shown on the picture below.</p>
<p><figure id="attachment_3002" style="width: 618px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Rabin-Karp-Brute-Froce-Principles.png"><img src="/wp-content/uploads/2012/04/Rabin-Karp-Brute-Froce-Principles.png" alt="Brute Froce Principles" title="Brute Froce Principles" width="618" height="242" class="size-full wp-image-3002" srcset="/wp-content/uploads/2012/04/Rabin-Karp-Brute-Froce-Principles.png 618w, /wp-content/uploads/2012/04/Rabin-Karp-Brute-Froce-Principles-300x117.png 300w" sizes="(max-width: 618px) 100vw, 618px" /></a><figcaption class="wp-caption-text">Brute force string matching is slow because it compares every single character from the pattern and the text!</figcaption></figure><span id="more-2991"></span></p>
<p>This algorithm is slow for mainly two reasons. First we have to check every single character from the text. On the other hand even if we find a match between a text character and the first character of the pattern we continue to check step by step (character by character) every single symbol of the pattern in order to find whether it is in the text. So is there any other approach to find whether the text contains the pattern?</p>
<p>In fact there is a “faster” approach. In this case in order to avoid the comparison between the pattern and the text character by character, we’ll try to compare them at once, so we need a good hash function. With its help we can hash the pattern and check against hashed sub-strings of the text. We must be sure that the hash function is returning “small” hash codes for larger sub-strings. Another problem is that for larger patterns we can’t expect to have short hashes. But besides this the approach should be quite effective compared to the brute force string matching. </p>
<p>That approach is known as Rabin-Karp algorithm.</p>
<h2>Overview</h2>
<p><a href="http://en.wikipedia.org/wiki/Michael_O._Rabin" title="Michael O. Rabin" target="_blank">Michael O. Rabin</a> and <a href="http://en.wikipedia.org/wiki/Richard_M._Karp" title="Richard M. Karp" target="_blank">Richard M. Karp</a> came up with the idea of hashing the pattern and to check it against a hashed sub-string from the text in 1987. In general the idea seems quite simple, the only thing is that we need a hash function that gives different hashes for different sub-strings. Such hash function, for instance, may use the ASCII codes for every character, but we must be careful for multi-lingual support.</p>
<figure id="attachment_3003" style="width: 621px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Rabin-Karp-Basic-Principles.png"><img src="/wp-content/uploads/2012/04/Rabin-Karp-Basic-Principles.png" alt="Rabin-Karp Basic Principles" title="Rabin-Karp Basic Principles" width="621" height="299" class="size-full wp-image-3003" srcset="/wp-content/uploads/2012/04/Rabin-Karp-Basic-Principles.png 621w, /wp-content/uploads/2012/04/Rabin-Karp-Basic-Principles-300x144.png 300w" sizes="(max-width: 621px) 100vw, 621px" /></a><figcaption class="wp-caption-text">Rabin-Karp hashes the pattern and the sub-string in order to compare them quickly!</figcaption></figure>
<p>The hash function may vary depending on many things, so it may consist of ASCII char to number converting, but it can be also anything else. The only thing we need is to convert a string (pattern) into some hash that is faster to compare. Let’s say we have the string “hello world”, and let’s assume that its hash is hash(‘hello world’) = 12345. So if hash(‘he’) = 1 we can say that the pattern “he” is contained in the text “hello world”. Thus on every step we take from the text a sub-string with the length of m, where m is the pattern length. Thus we hash this sub-string and we can directly compare it to the hashed pattern, as on the picture above.</p>
<h2>Implementation</h2>
<p>So far we saw some diagrams explaining the Rabin-Karp algorithm, but let’s take a look on its implementation. Here in this very basic example where a simple hash table is used in order to convert the characters into integers. The code is PHP and it&#8217;s used only to illustrate the principles of this algorithm.</p>
<pre lang="PHP">
function hash_string($str, $len)
{
	$hash = '';
 
	$hash_table = array(
		'h' => 1,
		'e' => 2,
		'l' => 3,
		'o' => 4,
		'w' => 5,
		'r' => 6,
		'd' => 7,
	);
 
	for ($i = 0; $i < $len; $i++) {
		$hash .= $hash_table[$str{$i}];
	}
 
	return (int)$hash;
}
 
function rabin_karp($text, $pattern)
{
	$n = strlen($text);
	$m = strlen($pattern);
 
	$text_hash = hash_string(substr($text, 0, $m), $m);
	$pattern_hash = hash_string($pattern, $m);
 
	for ($i = 0; $i < $n-$m+1; $i++) {
		if ($text_hash == $pattern_hash) {
			return $i;
		}
 
		$text_hash = hash_string(substr($text, $i, $m), $m);
	}
 
	return -1;
}
 
// 2
echo rabin_karp('hello world', 'ello');
</pre>
<h3>Multiple Pattern Match</h3>
<p>It’s great to say that the Rabin-Karp algorithm is great for multiple pattern match. Indeed its nature is supposed to support such functionality, which is its advantage in compare to other string searching algorithms.</p>
<h2>Complexity</h2>
<p>The Rabin-Karp algorithm has the complexity of O(nm) where <strong>n</strong>, of course, is the length of the text, while <strong>m</strong> is the length of the pattern. So where it is compared to brute-force matching? Well, brute force matching complexity is O(nm), so as it seems there’s no much gain in performance. However it’s considered that Rabin-Karp’s complexity is O(n+m) in practice, and that makes it a bit faster, as shown on the chart below.</p>
<figure id="attachment_3001" style="width: 600px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Rabin-Karp-Complexity.png"><img src="/wp-content/uploads/2012/04/Rabin-Karp-Complexity.png" alt="Rabin-Karp Complexity" title="Rabin-Karp Complexity" width="600" height="371" class="size-full wp-image-3001" srcset="/wp-content/uploads/2012/04/Rabin-Karp-Complexity.png 600w, /wp-content/uploads/2012/04/Rabin-Karp-Complexity-300x185.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><figcaption class="wp-caption-text">Rabin-Karp&#039;s complexity is O(nm), but in practice it&#039;s O(n+m)!</figcaption></figure>
<p>Note that the Rabin-Karp algorithm also needs O(m) preprocessing time.</p>
<h2>Application</h2>
<p>As we saw Rabin-Karp is not so faster than brute force matching. So where we should use it?</p>
<h3>3 Reasons Why Rabin-Karp is Cool</h3>
<p>1. Good for plagiarism, because it can deal with multiple pattern matching!<br />
<figure id="attachment_3000" style="width: 620px" class="wp-caption alignnone"><a href="/wp-content/uploads/2012/04/Application-of-Rabin-Karp.png"><img src="/wp-content/uploads/2012/04/Application-of-Rabin-Karp.png" alt="Application of Rabin-Karp" title="Application of Rabin-Karp" width="620" height="399" class="size-full wp-image-3000" srcset="/wp-content/uploads/2012/04/Application-of-Rabin-Karp.png 620w, /wp-content/uploads/2012/04/Application-of-Rabin-Karp-300x193.png 300w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption class="wp-caption-text">Rabin-Karp can detect plagiarism efficiently!</figcaption></figure></p>
<p>2. Not faster than brute force matching in theory, but in practice its complexity is O(n+m)!<br />
3. With a good hashing function it can be quite effective and it's easy to implement!</p>
<h3>2 Reasons Why Rabin-Karp is Not Cool</h3>
<p>1. There are lots of string matching algorithms that are faster than O(n+m)<br />
2. It’s practically as slow as brute force matching and it requires additional space</p>
<h2>Final Words</h2>
<p>Rabin-Karp is a great algorithm for one simple reason - it can be used to match against multiple pattern. This makes it perfect to detect plagiarism even for larger phrases. </p>
<div class='yarpp-related-rss'>
<p>Related posts:<ol>
<li><a href="/2012/04/09/computer-algorithms-morris-pratt-string-searching/" rel="bookmark" title="Computer Algorithms: Morris-Pratt String Searching">Computer Algorithms: Morris-Pratt String Searching </a></li>
<li><a href="/2012/04/17/computer-algorithms-boyer-moore-string-search-and-matching/" rel="bookmark" title="Computer Algorithms: Boyer-Moore String Searching">Computer Algorithms: Boyer-Moore String Searching </a></li>
<li><a href="/2012/03/27/computer-algorithms-brute-force-string-matching/" rel="bookmark" title="Computer Algorithms: Brute Force String Matching">Computer Algorithms: Brute Force String Matching </a></li>
<li><a href="/2011/08/18/powerful-php-less-known-string-manipulation/" rel="bookmark" title="Powerful PHP: Less Known String Manipulation">Powerful PHP: Less Known String Manipulation </a></li>
</ol></p>
</div>
]]></content:encoded>
			<wfw:commentRss>/2012/04/02/computer-algorithms-rabin-karp-string-searching/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
