Как найти последовательность значений (в частности, байты) в более крупной коллекции в .NET
Вопрос
Мне нужно проанализировать байты из файла, чтобы я брал данные только после того, как была идентифицирована определенная последовательность байтов.Например, если последовательность равна просто 0xFF (один байт), то я могу использовать LINQ для коллекции:
byte[] allBytes = new byte[] {0x00, 0xFF, 0x01};
var importantBytes = allBytes.SkipWhile(byte b => b != 0xFF);
// importantBytes = {0xFF, 0x01}
Но есть ли элегантный способ обнаружить многобайтовую последовательность - например0xFF, 0xFF - особенно тот, который возвращается в случае, если он начинает получать ложноположительное совпадение?
Решение
Я не знаю ни о каком встроенном способе;как обычно, вы всегда можете написать свой собственный метод расширения.Вот один из них, который приходит мне в голову (возможно, есть более эффективные способы его реализации):
public static IEnumerable<T> AfterSequence<T>(this IEnumerable<T> source,
T[] sequence)
{
bool sequenceFound = false;
Queue<T> currentSequence = new Queue<T>(sequence.Length);
foreach (T item in source)
{
if (sequenceFound)
{
yield return item;
}
else
{
currentSequence.Enqueue(item);
if (currentSequence.Count < sequence.Length)
continue;
if (currentSequence.Count > sequence.Length)
currentSequence.Dequeue();
if (currentSequence.SequenceEqual(sequence))
sequenceFound = true;
}
}
}
Мне нужно будет проверить, чтобы убедиться, что это правильно, но это должно дать вам основную идею;выполняйте итерацию по элементам, отслеживайте последнюю последовательность извлеченных значений, устанавливайте флаг, когда последовательность найдена, и, как только флаг установлен, начинайте возвращать каждый последующий элемент.
Редактировать - я действительно запустил тест, и он работает корректно.Вот несколько тестовых кодов:
static void Main(string[] args)
{
byte[] data = new byte[]
{
0x01, 0x02, 0x03, 0x04, 0x05,
0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA
};
byte[] sequence = new byte[] { 0x02, 0x03, 0x04, 0x05 };
foreach (byte b in data.AfterSequence(sequence))
{
Console.WriteLine(b);
}
Console.ReadLine();
}
Другие советы
Если вы преобразуете свои байты в строку, вы можете воспользоваться множеством встроенных в нее функций поиска, даже если байты, с которыми вы работаете, на самом деле не являются символами в традиционном смысле.
Просто в качестве небольшой теории;это обычная языковая проблема.Возможно, вы сможете использовать механизм регулярных выражений для его обнаружения.Найден первый поиск в Google по запросу "регулярное выражение в потоке"
http://codeguru.earthweb.com/columns/experts/article.php/c14689