【问题标题】:How to build byte array from bytes and nibbles in C#如何在 C# 中从字节和半字节构建字节数组
【发布时间】:2019-04-19 21:10:50
【问题描述】:

给定字符串数组的这种结构

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

如何获得content 等效的字节数组表示?我知道如何转换“5”、“7”和“0x66”,但我正在努力构建数组中半字节0x1、0x8 的整个字节数组表示......基本上我不知道如何将 "0x1", "5", "0x8" 连接到两个字节...

附加信息:字符串数组的序列仅包含字节或半字节数据。前缀为“0x”,一个数字被解释为半字节,没有前缀的数字应该被解释为字节,带有两个数字的十六进制字符串应该被解释为字节。

【问题讨论】:

  • 你是说有些字符串代表字节,有些代表半字节?那么任何有两位数字的都是一个字节,而任何只有一个数字的都是半字节?或者任何没有“0x”前缀的字节?请对您假设的语法非常具体。
  • 0x1 是一个字节,其最低有效位为高。仅当您打算将两个半字节打包成一个字节时,谈论半字节才有意义。如果你这样做了,你将无法区分正常字节和打包字节

标签: c#


【解决方案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

【讨论】:

  • 感谢 Dmitry 的付出!
【解决方案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 && s.StartsWith("0x"))
.Select(s => Convert.ToByte(s, 16))
.ToArray();

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

【讨论】:

    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多