Skip to content

C# 对 byte 数组进行模式搜索

Updated: at 08:22,Created: at 08:55

本文告诉大家几个方法从 byte 数组找到对应的相同序列的数组

最简单的方法是进行数值判断,但是代码最少是使用Linq ,效率比较高是使用 Boyer-Moore 算法,下面就告诉大家几个算法的代码

判断数值

class ByteArrayRocks
{
public static IEnumerable<int> IndexOf(byte[] source, int start, byte[] pattern)
{
if (IsEmptyLocate(source, start, pattern))
{
yield break;
}
for (int i = start; i < source.Length; i++)
{
if (!IsMatch(source, i, pattern))
{
continue;
}
yield return i;
}
}
private static readonly int[] Empty = new int[0];
private static bool IsMatch(byte[] array, int position, byte[] candidate)
{
if (candidate.Length > (array.Length - position))
{
return false;
}
for (int i = 0; i < candidate.Length; i++)
{
if (array[position + i] != candidate[i])
{
return false;
}
}
return true;
}
private static bool IsEmptyLocate(byte[] array, int start, byte[] candidate)
{
return array == null
|| candidate == null
|| array.Length == 0
|| array.Length < start
|| candidate.Length == 0
|| candidate.Length + start > array.Length;
}
}

这是最简单的方法,参见 https://stackoverflow.com/a/283648/6116637

linq

这个方法的代码最少

class LinqArraySearch
{
public static IEnumerable<int> IndexOf(byte[] source, int start, byte[] pattern)
{
for (int i = start; i < source.Length; i++)
{
if (source.Skip(i).Take(pattern.Length).SequenceEqual(pattern))
{
yield return i;
}
}
}
}

Boyer-Moore-Horspool 搜索

这是最快的方法

class BoyerMooreHorspool
{
public static IEnumerable<long> IndexesOf(byte[] source, int start, byte[] pattern)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (pattern == null)
{
throw new ArgumentNullException(nameof(pattern));
}
long valueLength = source.LongLength;
long patternLength = pattern.LongLength;
if ((valueLength == 0) || (patternLength == 0) || (patternLength > valueLength))
{
yield break;
}
var badCharacters = new long[256];
for (var i = 0; i < 256; i++)
{
badCharacters[i] = patternLength;
}
var lastPatternByte = patternLength - 1;
for (long i = 0; i < lastPatternByte; i++)
{
badCharacters[pattern[i]] = lastPatternByte - i;
}
long index = start;
while (index <= valueLength - patternLength)
{
for (var i = lastPatternByte; source[index + i] == pattern[i]; i--)
{
if (i == 0)
{
yield return index;
break;
}
}
index += badCharacters[source[index + lastPatternByte]];
}
}
}

参见:https://stackoverflow.com/q/16252518/6116637

测试了三个方法的性能,请看下面

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.1.202
[Host] : .NET Core 2.0.9 (CoreCLR 4.6.26614.01, CoreFX 4.6.26614.01), 64bit RyuJIT
DefaultJob : .NET Core 2.0.9 (CoreCLR 4.6.26614.01, CoreFX 4.6.26614.01), 64bit RyuJIT
MethodMeanErrorStdDev
Linq13,332.8 us251.782 us466.694 us
ByteArrayRocks371.3 us7.327 us14.462 us
BoyerMooreHorspool108.3 us1.153 us1.079 us

其他方法请看下面

使用不安全代码的 Boyer Moore 算法 C# High Performance Boyer Moore Byte Array Search Algorithm


知识共享许可协议

原文链接: http://blog.lindexi.com/post/C-%E5%AF%B9-byte-%E6%95%B0%E7%BB%84%E8%BF%9B%E8%A1%8C%E6%A8%A1%E5%BC%8F%E6%90%9C%E7%B4%A2

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系