Как построить массив байтов из байтов и кусочков в C#

#c#

#c#

Вопрос:

Учитывая эту структуру строкового массива

 string[] content = {"0x1", "5", "0x8", "7", "0x66"};
 

Как получить content эквивалентное представление массива байтов? Я знаю, как преобразовать «5», «7» и «0x66», но я изо всех сил пытаюсь создать представление всего массива байтов из кусочков 0x1 0x8 в массиве… В принципе, я не знаю, как объединить « 0x1" , "5" , "0x8" в два байта…

Дополнительная информация: Последовательность массива строк содержит только байтовые или фрагментарные данные. Префикс «0x» и одна цифра должны быть интерпретированы как nibble, цифры без префикса должны быть интерпретированы как байт, шестнадцатеричные строки с двумя числами должны быть интерпретированы как байт.

Комментарии:

1. Вы хотите сказать, что некоторые из этих строк представляют байты, а некоторые представляют кусочки? Итак, все, что содержит две цифры, является байтом, а все, что содержит одну цифру, является кусочком? Или что-нибудь без префикса «0x» является байтом? Пожалуйста, будьте очень конкретны в отношении синтаксиса, который вы предполагаете.

2. 0x1 это байт, младший значащий бит которого является старшим. Разговор о кусочках имел бы смысл, только если вы хотели упаковать два кусочка в один байт. Если бы вы это сделали, у вас не было бы способа отличить обычные байты от упакованных

Ответ №1:

Если предполагается, что все элементы должны быть шестнадцатеричными, Linq и Convert достаточно:

 string[] content = {"0x1", "5", "0x8", "7", "0x66"};

byte[] result = content
  .Select(item => Convert.ToByte(item, 16))
  .ToArray();
 

Если "5" и "7" должны быть десятичными (поскольку они не начинаются с 0x ), мы должны добавить условие:

 byte[] result = content
  .Select(item => Convert.ToByte(item, item.StartsWith("0x", StringComparison.OrdinalIgnoreCase) 
    ? 16
    : 10))
  .ToArray();
 

Редактировать: Если мы хотим объединить кусочки, давайте извлекем для этого метод:

 private static byte[] Nibbles(IEnumerable<string> data) {
  List<byte> list = new List<byte>();

  bool head = true;

  foreach (var item in data) {
    byte value = item.StartsWith("0x", StringComparison.OrdinalIgnoreCase) 
      ? Convert.ToByte(item, 16)
      : Convert.ToByte(item, 10);

    // Do we have a nibble? 
    // 0xDigit (Length = 3) or Digit (Length = 1) are supposed to be nibble
    if (item.Length == 3 || item.Length == 1) { // Nibble
      if (head)                                 // Head
        list.Add(Convert.ToByte(item, 16));
      else                                      // Tail
        list[list.Count - 1] = (byte)(list[list.Count - 1] * 16   value);

      head = !head;
    }
    else { // Entire byte
      head = true;

      list.Add(value);
    }
  }

  return list.ToArray();
}

...

string[] content = { "0x1", "5", "0x8", "7", "0x66" };

Console.Write(string.Join(", ", Nibbles(content)
  .Select(item => $"0x{item:x2}").ToArray()));
 

Результат:

 // "0x1", "5" are combined into 0x15
// "0x8", "7" are combined into 0x87
// "0x66"  is treated as a byte 0x66
0x15, 0x87, 0x66
 

Комментарии:

1. Спасибо Дмитрию за ваши усилия!

Ответ №2:

Вы можете использовать Zip метод, чтобы объединить источник с тем же смещением источника на 1.

 string[] source = { "0x1", "5", "0x8", "7", "0x66" };
var offsetSource = source.Skip(1).Concat(new string[] { "" });

var bytes = source
.Zip(offsetSource, (s1, s2) => s1   s2)
.Where(s => s.Length == 4 amp;amp; s.StartsWith("0x"))
.Select(s => Convert.ToByte(s, 16))
.ToArray();

Console.WriteLine(String.Join(", ", bytes)); // Output: 21, 135, 102