PythonNoob
PythonNoob

Reputation: 1052

How to build byte array from bytes and nibbles in C#

Given this structure of a string array

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

How to get the content equivalent byte array representation? I know how to convert the "5", "7" and "0x66" but I'm struggling to build the whole byte array representation of the nibbles 0x1, 0x8 in the array... Basically I don't know how to concat the "0x1", "5", "0x8" to two bytes...

Additional Info: The sequence of the string array contains only byte or nibble data. Prefixed "0x" and one digit is to be intepreted as a nibble, digits without prefix should be intepreted as byte, hex strings with two numbers should be intepreted as byte.

Upvotes: 0

Views: 675

Answers (2)

Theodor Zoulias
Theodor Zoulias

Reputation: 43845

You can use the Zip method, to combine the source with the same source offset by 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 && s.StartsWith("0x"))
.Select(s => Convert.ToByte(s, 16))
.ToArray();

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

Upvotes: 0

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186813

If all items are supposed to be hexadecimal, Linq and Convert are enough:

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

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

If "5" and "7" are supposed to be decimal (since they don't start from 0x) we have to add a condition:

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

Edit: If we want to combine nibbles, let's extract a method for it:

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()));

Outcome:

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

Upvotes: 2

Related Questions