如何将 4 字节的二进制数据解包为 3 字节和 1 字节的值?

Posted

技术标签:

【中文标题】如何将 4 字节的二进制数据解包为 3 字节和 1 字节的值?【英文标题】:How to unpack 4 bytes of binary data as 3 byte and 1 byte values? 【发布时间】:2016-02-11 02:36:58 【问题描述】:

我有 4 个字节的二进制数据(big-endian)要解压。如果它包含两个 2 字节的无符号整数值,这将很简单:

a, b = data.unpack("C>C>")

但是如果数据包含一个 3 字节值 (a) 后跟一个 1 字节值 (b) 怎么办? unpack 方法似乎无法处理除 8 位、16 位、32 位和 64 位整数以外的格式。这是我想出的:

a, b = data.unpack("L>XC")   # "L>": unpack a 32-bit unsigned int (big-endian)
                             # "X":  rewind (skip back) one byte
                             # "C":  unpack an 8-bit unsigned int
a >>= 8                      # drop the last (lowest) byte from a

(如果数据是 little-endian,则可以使用 a &= 0xFFFFFF 删除最后一个(最高)字节。)

有没有更优雅的方式来解压这些值?

【问题讨论】:

【参考方案1】:

这是一种合理的方式。另一种方式(不涉及备份)是

a, b, c = data.unpack("S>CC") # C doesn't have endianness
ab = a << 8 + b

由于您的值是无符号的,因此在将它们粘贴在一起时无需担心符号扩展。

为了完整起见,您还可以采取相反的方向 - 解压缩单个 32 位 int 并使用位操作将其拆分。

ab, = data.unpack("L>")
a, b = ab >> 8, ab & 0xFF

【讨论】:

【参考方案2】:

@hobbs 有一个很好的答案。我只是想提一下,在这种情况下你也可以使用Numeric#divmod

ab, = data.unpack('L>')
a, b = ab.divmod(2**8)

或者只是:

a, b = data.unpack('L>')[0].divmod(2**8)

【讨论】:

以上是关于如何将 4 字节的二进制数据解包为 3 字节和 1 字节的值?的主要内容,如果未能解决你的问题,请参考以下文章

SSE指令:字节+短

如何从二进制文件中读取块并使用 Python 或 Perl 解包提取结构?

如何从字节数组元素中解包/提取低阶和高阶值

如何将 Alteryx .yxzp 文件解包为较低版本

PHP如何将从二进制文件中读取的字节转换为数字

使用 Ruby 从二进制字符串中解包一点