Converting bits to bytes in Python
The simplest tactics to consume bits in 8-er chunks and ignore exceptions:
def getbytes(bits): done = False while not done: byte = 0 for _ in range(0, 8): try: bit = next(bits) except StopIteration: bit = 0 done = True byte = (byte << 1) | bit yield byte
Usage:
lst = [1,0,0,0,0,0,0,0,1]for b in getbytes(iter(lst)): print b
getbytes
is a generator and accepts a generator, that is, it works fine with large and potentially infinite streams.
Step 1: Add in buffer zeros
Step 2: Reverse bits since your endianness is reversed
Step 3: Concatenate into a single string
Step 4: Save off 8 bits at a time into an array
Step 5: ???
Step 6: Profit
def bitsToBytes(a): a = [0] * (8 - len(a) % 8) + a # adding in extra 0 values to make a multiple of 8 bits s = ''.join(str(x) for x in a)[::-1] # reverses and joins all bits returnInts = [] for i in range(0,len(s),8): returnInts.append(int(s[i:i+8],2)) # goes 8 bits at a time to save as ints return returnInts
Using itertools
' grouper()` recipe:
from functools import reducefrom itertools import zip_longestdef grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fillvalue)bytes = [reduce(lambda byte, bit: byte << 1 | bit, eight_bits) for eight_bits in grouper(bits, 8, fillvalue=0)]
Example
[] -> [][1] -> [128][1, 1] -> [192][1, 0, 0, 0, 0, 0, 0, 0, 1] -> [128, 128]
If input is a string then a specialized solution might be faster:
>>> bits = '100000001'>>> padded_bits = bits + '0' * (8 - len(bits) % 8)>>> padded_bits'1000000010000000'>>> list(int(padded_bits, 2).to_bytes(len(padded_bits) // 8, 'big'))[128, 128]
The last byte is zero if len(bits) % 8 == 0
.