c# – 在字节数组中查找字节序列

前端之家收集整理的这篇文章主要介绍了c# – 在字节数组中查找字节序列前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个字节数组,希望找到一些字节的“出现”.

例如00 69 73 6F 6D,非常大的字节数组(> 50/100兆字节)

要么

更好的反向操作:在不知道代码的情况下搜索最常见的模式,代码应该能够从文件中读取并找到它.

解决方法

您可以使用Boyer-Moore算法有效地搜索字节数组中的字节序列.

这是我从the Wikipedia entry on Boyer-Moore的Java版本转换而来的C#版本.

  1. public sealed class BoyerMoore
  2. {
  3. readonly byte[] needle;
  4. readonly int[] charTable;
  5. readonly int[] offsetTable;
  6.  
  7. public BoyerMoore(byte[] needle)
  8. {
  9. this.needle = needle;
  10. this.charTable = makeByteTable(needle);
  11. this.offsetTable = makeOffsetTable(needle);
  12. }
  13.  
  14. public IEnumerable<int> Search(byte[] haystack)
  15. {
  16. if (needle.Length == 0)
  17. yield break;
  18.  
  19. for (int i = needle.Length - 1; i < haystack.Length;)
  20. {
  21. int j;
  22.  
  23. for (j = needle.Length - 1; needle[j] == haystack[i]; --i,--j)
  24. {
  25. if (j != 0)
  26. continue;
  27.  
  28. yield return i;
  29. i += needle.Length - 1;
  30. break;
  31. }
  32.  
  33. i += Math.Max(offsetTable[needle.Length - 1 - j],charTable[haystack[i]]);
  34. }
  35. }
  36.  
  37. static int[] makeByteTable(byte[] needle)
  38. {
  39. const int ALPHABET_SIZE = 256;
  40. int[] table = new int[ALPHABET_SIZE];
  41.  
  42. for (int i = 0; i < table.Length; ++i)
  43. table[i] = needle.Length;
  44.  
  45. for (int i = 0; i < needle.Length - 1; ++i)
  46. table[needle[i]] = needle.Length - 1 - i;
  47.  
  48. return table;
  49. }
  50.  
  51. static int[] makeOffsetTable(byte[] needle)
  52. {
  53. int[] table = new int[needle.Length];
  54. int lastPrefixPosition = needle.Length;
  55.  
  56. for (int i = needle.Length - 1; i >= 0; --i)
  57. {
  58. if (isPrefix(needle,i + 1))
  59. lastPrefixPosition = i + 1;
  60.  
  61. table[needle.Length - 1 - i] = lastPrefixPosition - i + needle.Length - 1;
  62. }
  63.  
  64. for (int i = 0; i < needle.Length - 1; ++i)
  65. {
  66. int slen = suffixLength(needle,i);
  67. table[slen] = needle.Length - 1 - i + slen;
  68. }
  69.  
  70. return table;
  71. }
  72.  
  73. static bool isPrefix(byte[] needle,int p)
  74. {
  75. for (int i = p,j = 0; i < needle.Length; ++i,++j)
  76. if (needle[i] != needle[j])
  77. return false;
  78.  
  79. return true;
  80. }
  81.  
  82. static int suffixLength(byte[] needle,int p)
  83. {
  84. int len = 0;
  85.  
  86. for (int i = p,j = needle.Length - 1; i >= 0 && needle[i] == needle[j]; --i,--j)
  87. ++len;
  88.  
  89. return len;
  90. }
  91. }

这是一些控制台应用测试代码

  1. public static void Main()
  2. {
  3. byte[] haystack = new byte[10000];
  4. byte[] needle = { 0x00,0x69,0x73,0x6F,0x6D };
  5.  
  6. // Put a few copies of the needle into the haystack.
  7.  
  8. for (int i = 1000; i <= 9000; i += 1000)
  9. Array.Copy(needle,haystack,i,needle.Length);
  10.  
  11. var searcher = new BoyerMoore(needle);
  12.  
  13. foreach (int index in searcher.Search(haystack))
  14. Console.WriteLine(index);
  15. }

注意Search()方法如何返回haystack中针头起始点的所有位置的索引.

如果您只是想要计数,您可以这样做:

  1. int count = new BoyerMoore(needle).Search(haystack).Count();

对于你的第二个问题:我假设你问的是找到最长的重复字节序列?

这是一个更加复杂 – 而且非常不同 – 的问题.如果你想要一个答案,你应该问一个单独的问题,但你应该阅读the Wikipedia entry on the “longest repeated substring problem”.

猜你在找的C#相关文章