C# 字节数组中的模式匹配

C# 字节数组中的模式匹配,c#,.net,linq,C#,.net,Linq,假设我有两个字节数组,每个数组包含一系列值,如: byte[] b = {50,60,70,80,90,10,20,1,2,3,4,5,50,2,3,1,2,3,4,5}; byte[] b2 = {1,2,3,4,5} 我可以比较这两个数组,并使用LinQ方法查找相等的值。这样,如果我比较这两个数组,结果将是b数组的索引,其中b2数组的索引中的值是匹配的 我一直试图精确地找到b2数组在b数组中重复出现的范围。我是说 if (TheLenghtOfSearch==5) {Now the ind

假设我有两个字节数组,每个数组包含一系列值,如:

byte[] b = {50,60,70,80,90,10,20,1,2,3,4,5,50,2,3,1,2,3,4,5};
byte[] b2 = {1,2,3,4,5}
我可以比较这两个数组,并使用LinQ方法查找相等的值。这样,如果我比较这两个数组,结果将是b数组的索引,其中b2数组的索引中的值是匹配的

我一直试图精确地找到b2数组在b数组中重复出现的范围。我是说

if (TheLenghtOfSearch==5) {Now the indexes of two regions must be return }
Result ->(7, 11), (15, 19)

if (TheLenghtOfSearch==2) {Now the indexes of around 9 regions where the two consecutive values in b2 recurred in b must be returned}
Result ->(7, 8), (15, 16), (8, 9), (13, 14), (16, 17), (9, 10), (17, 18), (10, 11), (18, 19)

我想这个解决方案更加数学化。

如果Linq不是您绝对需要的选项,您可以通过for循环获得结果:

public static IList<Tuple<int, int>> RecurringIndexes(Byte[] master, Byte[] toFind, int length) {
  List<Tuple<int, int>> result = new List<Tuple<int, int>>();

  // Let's return empty list ... Or throw appropriate exception
  if (Object.ReferenceEquals(null, master))
    return result;
  else if (Object.ReferenceEquals(null, toFind))
    return result;
  else if (length < 0)
    return result;
  else if (length > toFind.Length)
    return result;

  Byte[] subRegion = new Byte[length];

  for (int i = 0; i <= toFind.Length - length; ++i) {
    for (int j = 0; j < length; ++j)
      subRegion[j] = toFind[j + i];

    for (int j = 0; j < master.Length - length + 1; ++j) {
      Boolean counterExample = false;

      for (int k = 0; k < length; ++k)
        if (master[j + k] != subRegion[k]) {
          counterExample = true;

          break;
        }

      if (counterExample)
        continue;

      result.Add(new Tuple<int, int>(j, j + length - 1));
    }
  }

  return result;
}

....

byte[] b = {50,60,70,80,90,10,20,1,2,3,4,5,50,2,3,1,2,3,4,5};
byte[] b2 = { 1, 2, 3, 4, 5 };

// Returns 2 patterns: {(7, 11), (15, 19)}
IList<Tuple<int, int>> indice5 = RecurringIndexes(b, b2, 5); 
// Return 9 patterns: {(7, 8), (15, 16), (8, 9), (13, 14), (16, 17), (9, 10), (17, 18), (10, 11), (18, 19)}
IList<Tuple<int, int>> indice2 = RecurringIndexes(b, b2, 2);
公共静态IList递归索引(字节[]主,字节[]toFind,int-length){
列表结果=新列表();
//让我们返回空列表…或引发相应的异常
if(Object.ReferenceEquals(null,master))
返回结果;
else if(Object.ReferenceEquals(null,toFind))
返回结果;
else if(长度<0)
返回结果;
else if(长度>查找长度)
返回结果;
字节[]子区域=新字节[长度];

对于(inti=0;i我决定使用List,而不是array,因为它有更多用于此类操作的助手。 据我所知,深度=每个数组中必须相等的项数。这一个有效,请检查以下内容:

class Program
{
    static void Main(string[] args)
    {
        List<byte> b = new List<byte>() { 50, 60, 70, 80, 90, 10, 20, 1, 2, 3, 4, 5, 50, 2, 3, 1, 2, 3, 4, 5 };
        List<byte> b2 = new List<byte>() { 1, 2, 3, 4, 5 };
        SmartComparer comparer = new SmartComparer();
        //Setting the depth here, now the depth is = 5
        var result = comparer.CompareArraysWithDepth(b, b2, 5);
        foreach (var keyValuePair in result)
        {
            Console.WriteLine(String.Format("b[{0}]->b[{1}] are equal to b2[{2}]->b2[{3}]", keyValuePair.Key.Key,
                                            keyValuePair.Key.Value, keyValuePair.Value.Key, keyValuePair.Value.Value));
        }
    }
}

public class SmartComparer
{
    public Boolean CompareRange(List<byte> a, List<byte> b)
    {
        for (int i = 0; i < a.Count; i++)
        {
            if (a[i] != b[i])
            {
                return false;
            }
        }
        return true;
    }

    /// <summary>
    /// |
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="depth"></param>
    /// <returns>Key->range in 'a', Value->range in 'b'</returns>
    public List<KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>>> CompareArraysWithDepth(
        List<byte> a, List<byte> b, int depth)
    {
        var result = new List<KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>>>();
        if (depth > b.Count)
            throw new ArgumentException("Array 'b' item count should be more then depth");
        if(a.Count<b.Count)
            throw new ArgumentException("Array 'a' item count should be more then Array 'b' item count");
        for (int i = 0; i <= a.Count - depth; i++)
        {
            for (int j = 0; j <= b.Count - depth; j++)
            {
                if (CompareRange(a.GetRange(i, depth), b.GetRange(j, depth)))
                {
                    result.Add(new KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>>(new KeyValuePair<int, int>(i, i + depth-1), new KeyValuePair<int, int>(j, j + depth-1)));
                }
            }
        }
        return result;
    }
}
对于深度=2,此操作的结果为:

b[7]->b[8] are equal to b2[0]->b2[1]
b[8]->b[9] are equal to b2[1]->b2[2]
b[9]->b[10] are equal to b2[2]->b2[3]
b[10]->b[11] are equal to b2[3]->b2[4]
b[13]->b[14] are equal to b2[1]->b2[2]
b[15]->b[16] are equal to b2[0]->b2[1]
b[16]->b[17] are equal to b2[1]->b2[2]
b[17]->b[18] are equal to b2[2]->b2[3]
b[18]->b[19] are equal to b2[3]->b2[4]
对于深度=5,此操作的结果为:

b[7]->b[11] are equal to b2[0]->b2[4]
b[15]->b[19] are equal to b2[0]->b2[4]

在您的示例中,您试图得到什么样的结果?b数组中的索引您可以将字节数组转换为字符串并执行字符串搜索b数组中的索引列表,这些索引列表等于b2中的某个值?
Shai Aharoni
bad move!Dmitry,该列表始终为空,这意味着找不到模式。我已经运行了这两个测试用例(标记5和标记2)得到了{7,15},正如我所举例的。你能提供你的反例吗?这不是结果,例如(1,2,3,4,5)已经复发了两次,所以结果不是7和15,我的意思是下一个和后一个呢,另一个病例会更多complex@Jack:如果没有示例(或测试用例),要找出正确答案是相当困难的。如果我猜对了(请参阅我编辑的解决方案),这就是答案(我成功地得到了2和9个图案)这正是我一直在寻找的!!非常感谢您的帮助,现在它工作得非常完美。:)Maris,它再次只找到最后一个模式。可能有很多模式我不知道它们被添加到了我的答案中,结果被提供给控制台。它返回模式的所有条目!还要注意,在结果中,我使用“深度”=3如果这不是您试图得到的结果,那么我完全误解了您。请提供预期的结果nwer对于深度为3的“b”和“b2”,因此我可以理解你试图得到什么,想象一个循环模式以数字序列的形式出现N次。我想列出该模式循环出现的所有范围,不仅仅是一个特定的索引范围,这是我遇到的问题,比较两个数组没有问题正如我在问题中所说。
b[7]->b[11] are equal to b2[0]->b2[4]
b[15]->b[19] are equal to b2[0]->b2[4]