Boyer Moore Search Algorithm
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class BoyerMoore
{
private int[] _jumpTable;
private byte[] _pattern;
private int _patternLength;
public BoyerMoore()
{
}
public BoyerMoore(byte[] pattern)
{
SetPattern(pattern);
}
public void SetPattern(byte[] pattern)
{
_pattern = pattern;
_jumpTable = new int[256];
_patternLength = _pattern.Length;
for (var index = 0; index < 256; index++)
_jumpTable[index] = _patternLength;
for (var index = 0; index < _patternLength - 1; index++)
_jumpTable[_pattern[index]] = _patternLength - index - 1;
}
public unsafe int Search(byte[] searchArray, int startIndex = 0)
{
if (_pattern == null)
throw new Exception("Pattern has not been set.");
if (_patternLength > searchArray.Length)
throw new Exception("Search Pattern length exceeds search array length.");
var index = startIndex;
var limit = searchArray.Length - _patternLength;
var patternLengthMinusOne = _patternLength - 1;
var Moves = 0;
fixed (byte* pointerToByteArray = searchArray)
{
var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
fixed (byte* pointerToPattern = _pattern)
{
while (index <= limit)
{
var j = patternLengthMinusOne;
while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
j--;
if (j < 0)
return index;
index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
1);
Moves++;
}
}
}
return -1;
}
public unsafe (List<int>, int) SearchAll(byte[] searchArray, int startIndex = 0)
{
if (_pattern == null)
throw new Exception("Pattern has not been set.");
if (_patternLength > searchArray.Length)
throw new Exception("Search Pattern length exceeds search array length.");
var index = startIndex;
var limit = searchArray.Length - _patternLength;
var patternLengthMinusOne = _patternLength - 1;
var list = new List<int>();
var Moves = 0;
fixed (byte* pointerToByteArray = searchArray)
{
var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
fixed (byte* pointerToPattern = _pattern)
{
while (index <= limit)
{
var j = patternLengthMinusOne;
while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
j--;
if (j < 0)
list.Add(index);
index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
1);
Moves++;
}
}
}
return (list, Moves);
}
public int SuperSearch(byte[] searchArray, int nth, int start = 0)
{
var e = start;
var c = 0;
do
{
e = Search(searchArray, e);
if (e == -1)
return -1;
c++;
e++;
} while (c < nth);
return e - 1;
}
public static bool ContainsAny(byte[] sPattern, params byte[][] list)
{
return list.Select(v => new BoyerMoore(v)).Any(bm => bm.Search(sPattern) != -1);
}
public static bool ContainsAny(string sPattern, params string[] list)
{
return list.Select(s => new BoyerMoore(s.ToLower().GetBytes(Encoding.ASCII)))
.Any(bm => bm.Search(sPattern.ToLower().GetBytes(Encoding.ASCII)) != -1);
}
}