Joe*_*l B 11 c# linq buffer bytearray
我正在处理COM端口应用程序,我们有一个定义的可变长度数据包结构,我正在与微控制器通信.数据包具有开始和停止字节的分隔符.麻烦的是,有时读缓冲区可能包含无关的字符.看起来我总是得到整个数据包,只是在实际数据之前/之后的一些额外的喋喋不休.所以我有一个缓冲区,只要从COM端口收到新数据,我就会附加数据.搜索此缓冲区以查找可能出现的数据包的最佳方法是什么?例如:
说我的数据包分隔符是0xFF,我有一个数组
{ 0x00, 0xFF, 0x02, 0xDA, 0xFF, 0x55, 0xFF, 0x04 }
Run Code Online (Sandbox Code Playgroud)
如何创建一个函数/ LINQ-statment来返回以分隔符开头和结尾的所有子数组(几乎就像带有通配符的滑动相关器)?
该示例将返回以下3个数组:
{0xFF, 0x02, 0xDA, 0xFF}, {0xFF, 0x55, 0xFF}, and
{0xFF, 0x02, 0xDA, 0xFF, 0x55, 0xFF}
Run Code Online (Sandbox Code Playgroud)
Amy*_*Amy 16
虽然Trystan的答案在技术上是正确的,但他正在制作大量原始阵列的副本.如果起始数组很大并且有一堆分隔符,则会很快变大.这种方法通过仅使用原始数组和正在评估的当前段的数组来避免大量内存消耗.
public static List<ArraySegment<byte>> GetSubArrays(this byte[] array, byte delimeter)
{
if (array == null) throw new ArgumentNullException("array");
List<ArraySegment<byte>> retval = new List<ArraySegment<byte>>();
for (int i = 0; i < array.Length; i++)
{
if (array[i] == delimeter)
{
for (int j = i + 1; j < array.Length; j++)
{
if (array[j] == delimeter)
{
retval.Add(new ArraySegment<byte>(array, i + 1, j - i - 1));
}
}
}
}
return retval;
}
Run Code Online (Sandbox Code Playgroud)
可以这样使用:
static void Main(string[] args)
{
byte[] arr = new byte[] { 0x00, 0xFF, 0x02, 0xDA, 0xFF, 0x55, 0xFF, 0x04 };
List<ArraySegment<byte>> retval = GetSubArrays(arr, 0xFF);
// this also works (looks like LINQ):
//List<ArraySegment<byte>> retval = arr.GetSubArrays(0xFF);
byte[] buffer = new byte[retval.Select(x => x.Count).Max()];
foreach (var x in retval)
{
Buffer.BlockCopy(x.Array, x.Offset, buffer, 0, x.Count);
Console.WriteLine(String.Join(", ", buffer.Take(x.Count).Select(b => b.ToString("X2")).ToArray()));
}
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
以下是使用LINQ执行此操作的方法...
int[] list = new int[] { 0x00, 0xFF, 0x02, 0xDA, 0xFF, 0x55, 0xFF, 0x04 };
int MAXLENGTH = 10;
var windows = list.Select((element, i) => list.Skip(i).Take(MAXLENGTH));
var matched = windows.Where(w => w.First() == 0xFF);
var allcombinations = matched.SelectMany(m => Enumerable.Range(1, m.Count())
.Select(i => m.Take(i)).Where(x => x.Count() > 2 && x.Last() == 0xFF));
Run Code Online (Sandbox Code Playgroud)
或者使用索引:
int length = list.Count();
var indexes = Enumerable.Range(0, length)
.SelectMany(i => Enumerable.Range(3, Math.Min(length-i, MAXLENGTH))
.Select(count => new {i, count}));
var results = indexes.Select(index => list.Skip(index.i).Take(index.count))
.Where(x => x.First() == 0xFF && x.Last() == 0xFF);
Run Code Online (Sandbox Code Playgroud)