如何判断一个Byte数组中是否存在某些连续的数据

cnwolfs 2009-02-18 10:42:07
加精
例如我要判断如下的数组中是否存在0X68, 0X73, 0X5f, 0X62, 0X61, 0X79这些数据,如果存在,则把第一个元素的下标找出来


byte[] mBTCmdDataBase = {
0X00, 0X00, 0X00, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X00, 0X00, 0X03, 0X00, 0X00, 0X00, 0X04, 0X00, 0X00, 0X00, 0X04, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X06, 0X00, 0X00, 0X00, 0X06, 0X68, 0X73, 0X5f, 0X62, 0X61, 0X79, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 0X00, 0X00, 0X00, 0X20, 0X00, 0X00, 0X00, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X08
};


...全文
2350 88 打赏 收藏 转发到动态 举报
写回复
用AI写文章
88 条回复
切换为时间正序
请发表友善的回复…
发表回复
zs742946530888 2011-07-01
  • 打赏
  • 举报
回复
还有其他办法吗
xmj1984 2011-05-15
  • 打赏
  • 举报
回复
来学习下 我用了3n 循环
querystringcom 2011-03-03
  • 打赏
  • 举报
回复
用ArrayList过滤一下就可以了
章泽天 2010-12-18
  • 打赏
  • 举报
回复
我怎么看不到 8楼的回复!!!
cnwolfs 2009-02-27
  • 打赏
  • 举报
回复
ToBase64String不好,因为ToBase64String会把不足某个长度的字节串后面补上若干个“=”
cnwolfs 2009-02-27
  • 打赏
  • 举报
回复
备注一下,这个程序同时要运行到PPC中,主要是针对TCP通讯数据包的识别和分割,因此比较关注效率问题
cnwolfs 2009-02-27
  • 打赏
  • 举报
回复
多谢各位,我的评判是:
假如System.Array.IndexOf 的效率不低于For循环+if判断,则System.Array.IndexOf 是最优方案,编程也很简单
找出第一个字节相同,然后使用for循环判断之后的数据是否相同。
cnwolfs 2009-02-26
  • 打赏
  • 举报
回复
不清楚BitConverter.ToString的转换效率如何
cnwolfs 2009-02-26
  • 打赏
  • 举报
回复
[Quote=引用 77 楼 wuyi8808 的回复:]
引用 75 楼 cnwolfs 的回复:
System.Array.IndexOf 的效率不行吗?


不是 System.Array.IndexOf 的效率不行,而是应用场合不对。

System.Array.IndexOf 只能搜索单个元素,而你的要求是搜索一个数组,67楼的程序用 System.Array.IndexOf 来搜索数组的第一个元素,然后还要判断数组其余元素是否匹配,如果不匹配又得重新用 System.Array.IndexOf 来搜索数组的第一个元素,....,那还不如用61楼的程序直接了当,并且效…
[/Quote]

System.Array.IndexOf 搜索到单个元素,再判断之后的元素是否相同,就可以完成搜索了
querystringcom 2009-02-23
  • 打赏
  • 举报
回复
0X00, 0X00, 0X00, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,
0X04, 0X00, 0X00, 0X00, 0X03, 0X00, 0X00, 0X00, 0X04, 0X00, 0X00,
0X00, 0X04, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X00, 0X00,
0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X06,
0X00, 0X00, 0X00, 0X06, 0X68, 0X73, 0X5f, 0X62, 0X61, 0X79, 0X00,
0X00, 0X00, 0X00, 0X00, 0X07, 0X00, 0X00, 0X00, 0X20, 0X00, 0X00,
0X00, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X01, 0X00,
0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X08, 0X00, 0X00, 0X00, 0X08
上面这些都是什么意思啊
gaolei477 2009-02-23
  • 打赏
  • 举报
回复
哇!学习啊!
wuyi8808 2009-02-23
  • 打赏
  • 举报
回复
[Quote=引用 75 楼 cnwolfs 的回复:]
System.Array.IndexOf 的效率不行吗?
[/Quote]

不是 System.Array.IndexOf 的效率不行,而是应用场合不对。

System.Array.IndexOf 只能搜索单个元素,而你的要求是搜索一个数组,67楼的程序用 System.Array.IndexOf 来搜索数组的第一个元素,然后还要判断数组其余元素是否匹配,如果不匹配又得重新用 System.Array.IndexOf 来搜索数组的第一个元素,....,那还不如用61楼的程序直接了当,并且效率高。


System.Array.IndexOf 用于搜索单个元素是很好的,如果要搜索一个数组,就用61楼的程序更好了。
zgke 2009-02-23
  • 打赏
  • 举报
回复
KMP 学习了:)
cnwolfs 2009-02-23
  • 打赏
  • 举报
回复
System.Array.IndexOf 的效率不行吗?

咨询一下System.Array.IndexOf 的效率如何
cnming 2009-02-22
  • 打赏
  • 举报
回复
模式匹配的KMP算法详解

这种由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现的改进的模式匹配算法简称为KMP算法。大概学过信息学的都知道,是个比较难理解的算法,今天特把它搞个彻彻底底明明白白。

注意到这是一个改进的算法,所以有必要把原来的模式匹配算法拿出来,其实理解的关键就在这里,一般的匹配算法:

int Index(String S,String T,int pos)//参考《数据结构》中的程序
{
i=pos;j=1;//这里的串的第1个元素下标是1
while(i<=S.Length && j<=T.Length)
{
if(S[i]==T[j]){++i;++j;}
else{i=i-j+2;j=1;}//**************(1)
}
if(j>T.Length) return i-T.Length;//匹配成功
else return 0;
}

匹配的过程非常清晰,关键是当‘失配’的时候程序是如何处理的?回溯,没错,注意到(1)句,为什么要回溯,看下面的例子:

S:aaaaabababcaaa T:ababc

aaaaabababcaaa
ababc.(.表示前一个已经失配)
回溯的结果就是
aaaaabababcaaa
a.(babc)
如果不回溯就是
aaaaabababcaaa
aba.bc
这样就漏了一个可能匹配成功的情况
aaaaabababcaaa
ababc

为什么会发生这样的情况?这是由T串本身的性质决定的,是因为T串本身有前后'部分匹配'的性质。如果T为abcdef这样的,大没有回溯的必要。

改进的地方也就是这里,我们从T串本身出发,事先就找准了T自身前后部分匹配的位置,那就可以改进算法。

如果不用回溯,那T串下一个位置从哪里开始呢?

还是上面那个例子,T为ababc,如果c失配,那就可以往前移到aba最后一个a的位置,像这样:
...ababd...
ababc
->ababc

这样i不用回溯,j跳到前2个位置,继续匹配的过程,这就是KMP算法所在。这个当T[j]失配后,j应该往前跳的值就是j的next值,它是由T串本身固有决定的,与S串无关。

《数据结构》上给了next值的定义:
0 如果j=1
next[j]={Max{k|1<k<j且'p1...pk-1'='pj-k+1...pj-1'
1 其它情况

我当初看到这个头就晕了,其实它就是描述的我前面表述的情况,关于next[1]=0是规定的,这样规定可以使程序简单一些,如果非要定为其它的值只要不和后面的值冲突也是可以的;而那个Max是什么意思,举个例子:

T:aaab

...aaaab...
aaab
->aaab
->aaab
->aaab

像这样的T,前面自身部分匹配的部分不止两个,那应该往前跳到第几个呢?最近的一个,也就是说尽可能的向右滑移最短的长度。

OK,了解到这里,就看清了KMP的大部分内容,然后关键的问题是如何求next值?先不管它,先看如何用它来进行匹配操作,也就是说先假设已经有了next值。

将最前面的程序改写成:

int Index_KMP(String S,String T,int pos)
{
i=pos;j=1;//这里的串的第1个元素下标是1
while(i<=S.Length && j<=T.Length)
{
if(j==0 || S[i]==T[j]){++i;++j;} //注意到这里的j==0,和++j的作用就知道为什么规定next[1]=0的好处了
else j=next[j];//i不变(不回溯),j跳动
}
if(j>T.Length) return i-T.Length;//匹配成功
else return 0;
}

OK,是不是非常简单?还有更简单的,求next值,这也是整个算法成功的关键,从next值的定义来求太恐怖了,怎么求?前面说过了,next值表达的就是T串的自身部分匹配的性质,那么,我只要将T串和T串自身来一次匹配就可以求出来了,这里的匹配过程不是从头一个一个匹配,而是从T[1]和T[2]开始匹配,给出算法如下:

void get_next(String T,int &next[])
{
i=1;j=0;next[1]=0;
while(i<=T.Length)
{
if(j==0 || T[i]==T[j]){++i;++j; next[i]=j;/**********(2)*/}
else j=next[j];
}
}

看这个函数是不是非常像KMP匹配的函数,没错,它就是这么干的!注意到(2)语句逻辑覆盖的时候是T[i]==T[j]以及i前面的、j前面的都匹配的情况下,于是先自增,然后记下来next[i]=j,这样每当i有自增就会求得一个next[i],而j一定会小于等于i,于是对于已经求出来的next,可以继续求后面的next,而next[1]=0是已知,所以整个就这样递推的求出来了,方法非常巧妙。

这样的改进已经是很不错了,但算法还可以改进,注意到下面的匹配情况:

...aaac...
aaaa.
T串中的'a'和S串中的'c'失配,而'a'的next值指的还是'a',那同样的比较还是会失配,而这样的比较是多余的,如果我事先知道,当T[i]==T[j],那next[i]就设为next[j],在求next值的时候就已经比较了,这样就可以去掉这样的多余的比较。于是稍加改进得到:

void get_nextval(String T,int &next[])
{
i=1;j=0;next[1]=0;
while(i<=T.Length)
{
if(j==0 || T[i]==T[j])
{ ++i;++j;
if(T[i]!=T[j]) next[i]=j;
else next[i]=next[j];//消去多余的可能的比较,next再向前跳
}
else j=next[j];
}
}

匹配算法不变。

到此就完全弄清楚了,以前老觉得KMP算法好神秘,真不是人想出来的,其实不然,它只不过是对原有的算法进行了改进。可见基础的经典的东西还是很重要,你有本事‘废’了经典,就创造了进步。

CSharpEx 2009-02-22
  • 打赏
  • 举报
回复
mark
cnwolfs 2009-02-22
  • 打赏
  • 举报
回复
谢谢
System.Array.IndexOf 好像不错
cellblue 2009-02-22
  • 打赏
  • 举报
回复
mark
cnming 2009-02-22
  • 打赏
  • 举报
回复
纠正上面的错误




public int ArrayFindIndexOf(byte [] pBT, byte [] pMatch, int pStartIndex)
{
try
{
int mIndex = -1;

while (mIndex < 0)
{
mIndex = System.Array.IndexOf(pBT, pMatch[0], pStartIndex);
if (mIndex < pStartIndex)
{
return -1;
}
pStartIndex = mIndex + 1;

if (mIndex >= 0)
{
for (int i = 0; i < pMatch.Length; i++)
{
if (pBT[mIndex + i] != pMatch[i])
{
mIndex = -1;
break;
}
}
}
}
return mIndex;
}
catch (NullReferenceException NullEx)
{
throw NullEx;
}
catch (Exception Ex)
{
throw Ex;
}
}



wuyi8808 2009-02-22
  • 打赏
  • 举报
回复
对于一般的数据,61 楼的算法足够好了。

如果是对于下面这种变态的数据,KMP算法就有优势了,因为KMP算法不用在源串中返回,可以大大提高搜索效率。

using System;

class Program
{
static void Main()
{
int m = 10000000;
int n = 1000;
byte[] s0 = new byte[m];
byte[] s1 = new byte[n];

for (int i = 0; i < m - 1; i++) s0[i] = 1;
for (int i = 0; i < n - 1; i++) s1[i] = 1;
s0[m - 1] = s1[n - 1] = 2;

DateTime time0 = DateTime.Now;
int index = IndexOf(s0, s1);
DateTime time1 = DateTime.Now;

Console.WriteLine("index = {0}, 用时 {1} 秒", index, (time1 - time0).TotalSeconds);
// index = 9999000, 用时 28.703125 秒
}

// 在 s 中查找 pattern 。
// 如果找到,返回 pattern 在 s 中第一次出现的位置(0起始)。
// 如果没找到,返回 -1。
static int IndexOf(byte[] s, byte[] pattern)
{
// ...
}
}
加载更多回复(67)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧