C# Разделить байт[] по шестнадцатеричному значению в новый массив байтов[]

Я хочу взять данные из IP-пакета, который представляет собой массив байтов, и разделить его на набор массивов байтов, начинающихся с 0x47, т.е. транспортные пакеты mpeg-2.

Например, исходный массив байтов выглядит так:

08 FF FF 47 FF FF FF 47 FF FF 47 FF 47 FF FF FF FF 47 FF FF 

Как бы вы разделили массив байтов на 0x47 и сохранили разделитель 0x47, чтобы он выглядел так? В порядке слов массив массивов байтов, которые начинаются с определенного шестнадцатеричного числа?

[0] 08 FF FF
[1] 47 FF FF FF
[2] 47 FF FF
[3] 47 FF
[4] 47 FF FF FF FF
[5] 47 FF FF

person Jonathan Kittell    schedule 24.06.2016    source источник
comment
Почему бы просто не пройти через это? Я полагаю, это должно сработать за время O(2n).   -  person Nikhil Girraj    schedule 24.06.2016


Ответы (4)


Вы можете легко реализовать требуемый сплиттер:

public static IEnumerable<Byte[]> SplitByteArray(IEnumerable<Byte> source, byte marker) {
  if (null == source)
    throw new ArgumentNullException("source");

  List<byte> current = new List<byte>();

  foreach (byte b in source) {
    if (b == marker) {
      if (current.Count > 0)
        yield return current.ToArray();

      current.Clear();
    }

    current.Add(b);
  }

  if (current.Count > 0)
    yield return current.ToArray();
}

и используйте его:

  String source = "08 FF FF 47 FF FF FF 47 FF FF 47 FF 47 FF FF FF FF 47 FF FF";

  // the data
  Byte[] data = source
    .Split(' ')
    .Select(x => Convert.ToByte(x, 16))
    .ToArray();

  // splitted
  Byte[][] result = SplitByteArray(data, 0x47).ToArray();

  // data splitted has been represented for testing
  String report = String.Join(Environment.NewLine, 
    result.Select(line => String.Join(" ", line.Select(x => x.ToString("X2")))));

  // 08 FF FF
  // 47 FF FF FF
  // 47 FF FF
  // 47 FF
  // 47 FF FF FF FF
  // 47 FF FF
  Console.Write(report);
person Dmitry Bychenko    schedule 24.06.2016

Возможное решение:

byte[] source = // ...
string packet = String.Join(" ", source.Select(b => b.ToString("X2")));

// chunks is of type IEnumerable<IEnumerable<byte>>
var chunks = Regex.Split(packet, @"(?=47)")
             .Select(c =>
                 c.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                 .Select(x => Convert.ToByte(x, 16)));
person Matias Cicero    schedule 24.06.2016

Возможно, это слишком хакерски для вас, но должно работать нормально:

string ins = "08 FF FF 47 FF FF FF 47 FF FF 47 FF 47 FF FF FF FF 47 FF FF ";
string[] splits = ins.Split(new string[] { "47" }, StringSplitOptions.None);
for (int i = 0; i < splits.Length; i++) {
     splits[i] = "47 " + splits[i];
}

Изменить: похоже на уже существующий ответ, я думаю.

person pay    schedule 24.06.2016

Есть несколько способов сделать это, самый простой подход - просто использовать .Split() и заменить значение, на которое разбивается.

string[] values = packet.Split("47");
for(int i = 0; i < values.Length; i++)
{
    Console.WriteLine("[{0}] 47 {1}", i, values[i]);
    // C# 6+ way: Console.WriteLine($"[{i}] 47 {values[i]}");
}

Конечно, вы всегда можете использовать регулярные выражения, но мои навыки работы с регулярными выражениями довольно ограничены, и я не думаю, что смогу лично создать для этого действительное регулярное выражение.

person Ingenioushax    schedule 24.06.2016
comment
Это сработает, string[] mpegPackets = Regex.Split(data, "(?=47)"); я думаю, вы правы, мне нужно преобразовать шестнадцатеричные значения в строку, чтобы разделить. - person Jonathan Kittell; 24.06.2016
comment
Разве вопрос не в массиве bytes? - person Nikhil Girraj; 24.06.2016