【问题标题】:c# How to Continuously find a byte array inside a byte array?c#如何在字节数组中连续查找字节数组?
【发布时间】:2016-04-27 18:00:00
【问题描述】:

我试图在一个字节数组中不断地找到一个字节数组(byte[]),但我找到了一个只找到第一次出现的代码。

这是我找到代码的地方: Find an array (byte[]) inside another array?

问题:如何使用下面的代码连续查找字节数组?

        public int SearchBytes(byte[] haystack, byte[] needle)
    {
        int len = needle.Length;
        int limit = haystack.Length - len;
        for (int i = 0; i <= limit; i++)
        {
            int k = 0;
            for (; k < len; k++)
            {
                if (needle[k] != haystack[i + k]) break;
            }
            if (k == len) return i;
        }
        return -1;
    }

【问题讨论】:

  • 好吧,你试过什么?如果你想返回一个 List&lt;int&gt; 的匹配项,难道你不能将 return i 更改为 matches.Add(i) 并声明一个 List&lt;int&gt; matches = new List&lt;int&gt;() 开始吗?
  • 连续查找是指找到一个字节序列与另一个字节数组的所有出现?
  • @Gnqz 是的,我就是这个意思。
  • 看看the algorithm in this thread,得到正确答案。它使用 Boyer-Moore-Horspool 算法,速度非常快。

标签: c# arrays search find byte


【解决方案1】:

你可以改变方法来接受这样的开始索引:

public int SearchBytes(byte[] haystack, byte[] needle, int start_index)
{
    int len = needle.Length;
    int limit = haystack.Length - len;
    for (int i = start_index; i <= limit; i++)
    {
        int k = 0;
        for (; k < len; k++)
        {
            if (needle[k] != haystack[i + k]) break;
        }
        if (k == len) return i;
    }
    return -1;
}

区别只是这个方法接受start_index并在这个特定的索引处开始搜索。

现在,你可以这样使用它:

byte[] haystack = new byte[] { 1, 2, 3, 4, 5, 1, 2, 3 };

byte[] needle = new byte[] {1,2,3};

int index = 0;

while (true)
{
    index = SearchBytes(haystack, needle, index);

    if (index == -1)
        break;

    Console.WriteLine("Found at " + index);

    index += needle.Length;
}

这个循环从索引 0 开始,然后它使用上一次搜索的结果来设置一个新的索引来开始下一次搜索。

它将needle.Length 添加到索引中,以便我们在先前找到的结果结束后立即开始搜索。

更新:

下面是如何使用这段代码创建一个以数组形式返回索引的方法:

public int[] SearchBytesMultiple(byte[] haystack, byte[] needle)
{
    int index = 0;

    List<int> results = new List<int>();

    while (true)
    {
        index = SearchBytes(haystack, needle, index);

        if (index == -1)
            break;

        results.Add(index);

        index += needle.Length;
    }

    return results.ToArray();
}

而且可以这样使用:

byte[] haystack = new byte[] { 1, 2, 3, 4, 5, 1, 2, 3 };

byte[] needle = new byte[] {1,2,3};

int[] indexes = SearchBytesMultiple(haystack, needle);

【讨论】:

  • 我尝试了你的答案并抛出异常:索引超出了数组的范围。
  • 哪一行抛出异常?您是否按原样获取方法代码?它有两处变化。
  • 这是个例外: if (needle[k] != haystack[i + k]) break;我取了'int index = 0'并将它放在void(这是一个按钮)之外,我得到了一个异常,否则如果我保持原样,它就不会再出现了。
  • 为什么要移动int index = 0?它现在是一个实例变量吗?代码现在看起来如何?
  • 它现在可以工作了,我不得不删除 while (true)。我不确定为什么要修复它。此外,我不得不移动索引,因为每次单击按钮时它都会将其重置为 0。这是固定版本:byte[] haystack = new byte[] { 1, 2, 1, 1, 5, 1, 1, 1 }; byte[] needle = new byte[] { 1 }; index = SearchBytes(haystack, needle, index); Console.WriteLine("Found at " + index); index += needle.Length;
【解决方案2】:

作为替代方案,您可以考虑使用Boyer-Moore algorithm,如果needle[]haystack[] 的大小很大,它的性能非常好。

但是,我不建议在很短的needle[]haystack[] 上使用此方法,因为设置偏移表的开销将高于仅执行简单的线性搜索。

这是我从我链接的 Wiki 页面上的 Java 转换而来的实现:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
    public sealed class BoyerMoore
    {
        readonly byte[] needle;
        readonly int[]  charTable;
        readonly int[]  offsetTable;

        public BoyerMoore(byte[] needle)
        {
            this.needle      = needle;
            this.charTable   = makeByteTable(needle);
            this.offsetTable = makeOffsetTable(needle);
        }

        public IEnumerable<int> Search(byte[] haystack)
        {
            if (needle.Length == 0)
                yield break;

            for (int i = needle.Length - 1; i < haystack.Length;)
            {
                int j;

                for (j = needle.Length - 1; needle[j] == haystack[i]; --i, --j)
                {
                    if (j != 0)
                        continue;

                    yield return i;
                    i += needle.Length - 1;
                    break;
                }

                i += Math.Max(offsetTable[needle.Length - 1 - j], charTable[haystack[i]]);
            }
        }

        static int[] makeByteTable(byte[] needle)
        {
            const int ALPHABET_SIZE = 256;
            int[] table = new int[ALPHABET_SIZE];

            for (int i = 0; i < table.Length; ++i)
                table[i] = needle.Length;

            for (int i = 0; i < needle.Length - 1; ++i)
                table[needle[i]] = needle.Length - 1 - i;

            return table;
        }

        static int[] makeOffsetTable(byte[] needle)
        {
            int[] table = new int[needle.Length];
            int lastPrefixPosition = needle.Length;

            for (int i = needle.Length - 1; i >= 0; --i)
            {
                if (isPrefix(needle, i + 1))
                    lastPrefixPosition = i + 1;

                table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
            }

            for (int i = 0; i < needle.Length - 1; ++i)
            {
                int slen = suffixLength(needle, i);
                table[slen] = needle.Length - 1 - i + slen;
            }

            return table;
        }

        static bool isPrefix(byte[] needle, int p)
        {
            for (int i = p, j = 0; i < needle.Length; ++i, ++j)
                if (needle[i] != needle[j])
                    return false;

            return true;
        }

        static int suffixLength(byte[] needle, int p)
        {
            int len = 0;

            for (int i = p, j = needle.Length - 1; i >= 0 && needle[i] == needle[j]; --i, --j)
                ++len;

            return len;
        }
    }
}

这是一些测试代码:

byte[] haystack = new byte[1000];
byte[] needle   = {1, 2, 3, 4, 5, 6, 7, 8, 9};

for (int i = 100; i <= 900; i += 100)
    Array.Copy(needle, 0, haystack, i, needle.Length);

var searcher = new BoyerMoore(needle);

foreach (int index in searcher.Search(haystack))
    Console.WriteLine(index);

【讨论】:

    猜你喜欢
    • 2011-12-20
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 2012-07-07
    • 1970-01-01
    • 2014-02-15
    相关资源
    最近更新 更多