在 Python 中进行位域操作的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:26:00  来源:igfitidea点击:

What is the best way to do Bit Field manipulation in Python?

pythonudpbitsbit-fields

提问by ZebZiggle

I'm reading some MPEG Transport Stream protocol over UDP and it has some funky bitfields in it (length 13 for example). I'm using the "struct" library to do the broad unpacking, but is there a simple way to say "Grab the next 13 bits" rather than have to hand-tweak the bit manipulation? I'd like something like the way C does bit fields (without having to revert to C).

我正在阅读一些基于 UDP 的 MPEG 传输流协议,其中包含一些时髦的位域(例如,长度为 13)。我正在使用“struct”库进行广泛的解包,但是有没有一种简单的方法可以说“抓住接下来的 13 位”而不是手动调整位操作?我想要类似于 C 处理位域的方式(不必恢复到 C)。

Suggestions?

建议?

采纳答案by Thomas Vander Stichele

It's an often-asked question. There's an ASPN Cookbookentry on it that has served me in the past.

这是一个经常被问到的问题。上面有一个ASPN Cookbook条目,过去曾为我服务。

And there is an extensive page of requirements one person would like to see from a module doing this.

并且人们希望从执行此操作的模块中看到大量需求。

回答by Scott Griffiths

The bitstringmodule is designed to address just this problem. It will let you read, modify and construct data using bits as the basic building blocks. The latest versions are for Python 2.6 or later (including Python 3) but version 1.0 supported Python 2.4 and 2.5 as well.

模块旨在解决这个问题。它将允许您使用位作为基本构建块来读取、修改和构建数据。最新版本适用于 Python 2.6 或更高版本(包括 Python 3),但 1.0 版也支持 Python 2.4 和 2.5。

A relevant example for you might be this, which strips out all the null packets from a transport stream (and quite possibly uses your 13 bit field?):

一个与您相关的示例可能是这样,它从传输流中去除所有空数据包(并且很可能使用您的 13 位字段?):

from bitstring import Bits, BitStream  

# Opening from a file means that it won't be all read into memory
s = Bits(filename='test.ts')
outfile = open('test_nonull.ts', 'wb')

# Cut the stream into 188 byte packets
for packet in s.cut(188*8):
    # Take a 13 bit slice and interpret as an unsigned integer
    PID = packet[11:24].uint
    # Write out the packet if the PID doesn't indicate a 'null' packet
    if PID != 8191:
        # The 'bytes' property converts back to a string.
        outfile.write(packet.bytes)

Here's another example including reading from bitstreams:

这是另一个示例,包括从比特流中读取:

# You can create from hex, binary, integers, strings, floats, files...
# This has a hex code followed by two 12 bit integers
s = BitStream('0x000001b3, uint:12=352, uint:12=288')
# Append some other bits
s += '0b11001, 0xff, int:5=-3'
# read back as 32 bits of hex, then two 12 bit unsigned integers
start_code, width, height = s.readlist('hex:32, 2*uint:12')
# Skip some bits then peek at next bit value
s.pos += 4
if s.peek(1):
    flags = s.read(9)

You can use standard slice notation to slice, delete, reverse, overwrite, etc. at the bit level, and there are bit level find, replace, split etc. functions. Different endiannesses are also supported.

可以使用标准的切片符号在位级进行切片、删除、反转、覆盖等操作,还有位级查找、替换、拆分等功能。还支持不同的字节序。

# Replace every '1' bit by 3 bits
s.replace('0b1', '0b001')
# Find all occurrences of a bit sequence
bitposlist = list(s.findall('0b01000'))
# Reverse bits in place
s.reverse()

The full documentation is here.

完整的文档在这里