using System.Collections.Generic;
public static void Main()
string text = "zf3kabxcde224lkzf3mabxc51+crsdtzf3nab=";
Dictionary<string, int> patterns = PatternDiscovery(text, 3);
foreach (var item in patterns)
Console.WriteLine($"'{item.Key}': {item.Value}");
private static Dictionary<string, int> PatternDiscovery(string text, int patternLength)
Dictionary<string, int> patterns = new Dictionary<string, int>();
for (int i = 0; i < text.Length - patternLength; i++)
FindPattern(text, text.Substring(i, patternLength), patterns);
private static void FindPattern(string text, string pattern, Dictionary<string, int> patterns)
if (patterns.ContainsKey(pattern))
ISearch kmpSearch = new KnuthMorrisPratt();
List<int> searchResult = kmpSearch.Search(text, pattern)?.ToList();
if (searchResult != null && searchResult.Any() && searchResult.Count > 1)
patterns.Add(pattern, searchResult.Count);
IEnumerable<int> Search(string text, string pattern);
public class KnuthMorrisPratt : ISearch
public IEnumerable<int> Search(string text, string pattern)
int textLength = text.Length;
int patternLength = pattern.Length;
if (textLength < patternLength)
if (textLength == patternLength && text == pattern)
return new List<int>() { 0 };
return new List<int>() { 0 };
int[] lpsArray = new int[patternLength];
List<int> matchedIndex = new List<int>();
LongestPrefixSuffix(pattern, ref lpsArray);
while (textIndex < textLength)
if (text[textIndex] == pattern[patternIndex])
if (patternIndex == patternLength)
matchedIndex.Add(textIndex - patternIndex);
patternIndex = lpsArray[patternIndex - 1];
else if (textIndex < textLength && text[textIndex] != pattern[patternIndex])
patternIndex = lpsArray[patternIndex - 1];
private void LongestPrefixSuffix(string pattern, ref int[] lpsArray)
int patternLength = pattern.Length;
while (patternIndex < patternLength)
if (pattern[patternIndex] == pattern[len])
lpsArray[patternIndex] = len;
lpsArray[patternIndex] = 0;
public class RabinKarp : ISearch
readonly static int primeNumber = 101;
readonly static int d = 256;
public IEnumerable<int> Search(string text, string pattern)
List<int> resultIndex = new List<int>();
int patternLength = pattern.Length;
int textLength = text.Length;
for (i = 0; i < patternLength - 1; i++)
h = (h * d) % primeNumber;
for (i = 0; i < patternLength; i++)
patternHash = (d * patternHash + pattern[i]) % primeNumber;
textHash = (d * textHash + text[i]) % primeNumber;
for (i = 0; i <= textLength - patternLength; i++)
if (patternHash == textHash)
for (j = 0; j < patternLength; j++)
if (text[i + j] != pattern[j])
if (i < textLength - patternLength)
textHash = (d * (textHash - text[i] * h) + text[i + patternLength]) % primeNumber;
textHash = (textHash + primeNumber);
public class BoyerMoore : ISearch
public IEnumerable<int> Search(string text, string pattern)
List<int> retVal = new List<int>();
int patternLength = pattern.Length;
int textLength = text.Length;
int[] badChar = new int[256];
BadCharHeuristic(pattern, patternLength, ref badChar);
while (searchIndex <= (textLength - patternLength))
int patternIndex = patternLength - 1;
while (patternIndex >= 0 && pattern[patternIndex] == text[searchIndex + patternIndex])
searchIndex += (searchIndex + patternLength < textLength) ? patternLength - badChar[text[searchIndex + patternLength]] : 1;
searchIndex += Math.Max(1, patternIndex - badChar[text[searchIndex + patternIndex]]);
private static void BadCharHeuristic(string str, int size, ref int[] badChar)
for (i = 0; i < 256; i++)
for (i = 0; i < size; i++)
badChar[(int)str[i]] = i;
public class StringSearchTest
ISearch kmpSearch = new KnuthMorrisPratt();
AssertStringSearch(kmpSearch);
public void BoyerMoore_Test()
ISearch kmpSearch = new BoyerMoore();
AssertStringSearch(kmpSearch);
public void RabinKarp_Test()
ISearch kmpSearch = new RabinKarp();
AssertStringSearch(kmpSearch);
private void AssertStringSearch(ISearch searchAlgorithm)
string sampleText = "zf3kabxcde224lkzf3mabxc51+crsdtzf3nab=";
var pattern1Result = searchAlgorithm.Search(sampleText, pattern1).ToList();
Assert.NotNull(pattern1Result);
Assert.True(pattern1Result.Count() == 2);
Assert.Equal(4, pattern1Result[0]);
Assert.Equal(19, pattern1Result[1]);
var pattern2Result = searchAlgorithm.Search(sampleText, pattern2).ToList();
Assert.NotNull(pattern2Result);
Assert.True(pattern2Result.Count() == 3);
Assert.Equal(0, pattern2Result[0]);
Assert.Equal(15, pattern2Result[1]);
Assert.Equal(31, pattern2Result[2]);