Python 将包含11位整数的字节数组强制转换为16位整数数组

Python 将包含11位整数的字节数组强制转换为16位整数数组,python,arrays,numpy,cython,ctypes,Python,Arrays,Numpy,Cython,Ctypes,我有一个bytes对象或bytearray对象,表示11位整数的压缩流。(编辑:流是无填充的11位大端整数。) 是否有一种合理有效的方法将其复制到16位整数流?或任何其他整数类型 我知道ctypes支持位字段,但我不确定这是否对我有帮助 我是否可以“滥用”标准库的某些部分,这些部分已经为其他目的进行了这样的修改 如果我不得不求助于cython,是否有一个好的实现可以处理可变位长度?即,不仅适用于11位输入,还适用于12、13等 编辑:基于PM2 Ring答案的纯python解决方案 def u

我有一个bytes对象或bytearray对象,表示11位整数的压缩流。(编辑:流是无填充的11位大端整数。)

是否有一种合理有效的方法将其复制到16位整数流?或任何其他整数类型

我知道ctypes支持位字段,但我不确定这是否对我有帮助

我是否可以“滥用”标准库的某些部分,这些部分已经为其他目的进行了这样的修改

如果我不得不求助于cython,是否有一个好的实现可以处理可变位长度?即,不仅适用于11位输入,还适用于12、13等


编辑:基于PM2 Ring答案的纯python解决方案

def unpackIntegers(data, num_points, bit_len):
    """Unpacks an array of integers of arbitrary bit-length into a 
    system-word aligned array of integers"""
    # TODO: deal with native integer types separately for speedups
    mask = (1 << bit_len) - 1

    unpacked_bit_len = 2 ** ceil(log(bit_len, 2))
    unpacked_byte_len = ceil(unpacked_bit_len / 8)
    unpacked_array = bytearray(num_points * unpacked_byte_len)
    unpacked = memoryview(unpacked_array).cast(
        FORMAT_CODES[unpacked_byte_len])

    num_blocks = num_points // 8 

    # Note: zipping generators is faster than calculating offsets 
    #       from a block count
    for idx1_start, idx1_stop, idx2_start, idx2_stop in zip(
            range(0, num_blocks*bit_len, bit_len),
            range(bit_len, (num_blocks+1)*bit_len, bit_len),
            range(7, num_points, 8),
            range(-1, num_points-8, 8),
            ):
        n = int.from_bytes(data[idx1_start:idx1_stop], 'big')
        for i in range(idx2_start, idx2_stop, -1):
            unpacked[i] = n & mask
            n >>= bit_len
    # process left-over part (missing from PM2 Ring's answer)
    else:
        points_left = num_points % 8 
        bits_left = points_left * bit_len
        bytes_left = len(data)-num_blocks*bit_len
        num_unused_bits = bytes_left * 8 - bits_left

        n = int.from_bytes(data[num_blocks*bit_len:], 'big')
        n >>= num_unused_bits
        for i in range(num_points-1, num_points-points_left-1, -1):
            unpacked[i] = n & mask
            n >>= bit_len
    return unpacked
def解包整数(数据、点数、位长度):
“”“将任意位长度的整数数组解压为
系统字对齐整数数组“”
#TODO:分别处理本机整数类型以提高速度
掩码=(1>=位长度
#工艺遗留部分(PM2环的答案中缺失)
其他:
点数左=点数%8
位左=点左*位左
字节数=长度(数据)-块数*位长度
num_unused_bits=剩余字节数*8-剩余比特数
n=int.from_字节(数据[num_blocks*bit_len:],“big”)
n>>=num\u未使用的\u位
对于范围内的i(num_points-1,num_points-points_left-1,-1):
未打包的[i]=n&M
n>>=位长度
未包装退货

使用第三方库可能有更有效的方法,但这里有一种使用标准Python的方法

unpack
生成器以块的形式迭代其
data
参数,
data
可以是任何产生字节的iterable。要解包11位数据,我们读取11字节的块,将这些字节组合成一个整数,然后将该整数分割成8段,因此每段都包含来自相应1字节的数据1个源位

def unpack(data, bitlen):
    mask = (1 << bitlen) - 1
    for chunk in zip(*[iter(data)] * bitlen):
        n = int.from_bytes(chunk, 'big')
        a = []
        for i in range(8):
            a.append(n & mask)
            n >>= bitlen
        yield from reversed(a)

# Test

# 0 to 23 in 11 bit integers, packed into bytes
data = bytes([
    0, 0, 4, 1, 0, 48, 8, 1, 64, 48, 7, 
    1, 0, 36, 5, 0, 176, 24, 3, 64, 112, 15, 
    2, 0, 68, 9, 1, 48, 40, 5, 64, 176, 23,
])

print(list(unpack(data, 11)))
请注意,如果
数据
不包含多个
字节,则它将以将被忽略的部分块结束

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]