如何在Python中正确处理八位字节中的4位数据

2 投票
4 回答
681 浏览
提问于 2025-04-15 15:10

我正在写一个应用程序,用来解析某些网络数据包。一个数据包的字段里包含了协议的版本号,这个版本号用一个字节表示,其中高4位是“主版本号”,低4位是“次版本号”。现在我正在用以下方式来解析这些版本号,但我在想有没有更好看或者更符合Python风格的方法来做这件事:

    v = ord(data[17])
    major = (v & int('11110000',2) ) >> 4
    minor = v & int('00001111',2)

4 个回答

1

用字面量代替调用 int 会更整洁。比如,你可以使用二进制字面量或十六进制字面量:

major = (v & 0xf0) >> 4
minor = (v & 0x0f)

二进制字面量只适用于 Python 2.6 或更高版本,格式是 0b11110000。如果你使用的是 Python 2.6 或更高版本,可能想看看 bytearray 类型,因为它可以让你把数据当作二进制来处理,这样就不需要调用 ord 了。

如果你在解析二进制数据时发现需要进行很多位操作,可能想尝试一些更通用的解决方案,因为有一些第三方模块专门处理这个问题。其中一个是 hachoir(编辑:已删除无效链接 1/2023),还有一个更底层的选择是 bitstring(编辑:已删除无效链接 1/2023)(这是我写的)。在这种情况下,你的解析可能会变成这样:

major, minor = data.readlist('uint:4, uint:4')

如果你需要进行很多这样的读取,这样的方式会更容易管理。

2

给函数起个好名字总是个不错的主意,这样可以把那些复杂和不相关的内容隐藏起来。这样一来,处理细节的代码就集中在一些小的、容易验证正确的函数里,而更高层的代码则可以直接说明这些细节处理的目的。

def high_nibble(byte):
    """Get 4 high order bits from a byte."""
    return (byte >> 4) & 0xF

def low_nibble(byte):
    """Get 4 low order bits from a byte."""
    return byte & 0xF

def parse_version(version_byte):
    """Get the major-minor version tuple from the version byte."""
    return high_nibble(version_byte), low_nibble(version_byte)

major, minor = parse_version(version_byte)
3

你可以这样写二进制数字,比如0b1111000

不过对于你的例子,我可能会用十六进制来表示

v = ord(data[17])
major = (v & 0xF0) >> 4
minor = (v & 0x0F)

你可能还想使用struct模块来把数据包拆分成不同的部分

撰写回答