在 Python 中将二进制转换为带符号的小端 16 位整数

Convert binary to signed, little endian 16bit integer in Python

正在尝试将二进制列表转换为带符号的 16 位小端整数

input_data = [['1100110111111011','1101111011111111','0010101000000011'],['1100111111111011','1101100111111111','0010110100000011']]
Desired Output =[[-1074, -34, 810],[-1703, -39, 813]]

这就是我目前所知道的。它改编自:Hex string to signed int in Python 3.2?Conversion from HEX to SIGNED DEC in python

results = []
for i in input_data:
   hex_convert = [hex(int(x,2)) for x in i]
   convert = [int(y[4:6] + y[2:4], 16) for y in hex_convert]
   results.append(convert)
print (results)
output: [[64461, 65502, 810], [64463, 65497, 813]]

这很好用,但上面是无符号整数。我需要能够处理负值的有符号整数。然后我尝试了一种不同的方法:

results_2 = []
for i in input_data:
   hex_convert = [hex(int(x,2)) for x in i]
   to_bytes = [bytes(j, 'utf-8') for j in hex_convert]
   split_bits = [int(k, 16) for k in to_bytes]
   convert_2 = [int.from_bytes(b, byteorder = 'little', signed = True) for b in to_bytes]
   results_2.append(convert_2)
print (results_2)
Output: [[108191910426672, 112589973780528, 56282882144304], [108191943981104, 112589235583024, 56282932475952]]

这个结果比第一个更疯狂。我知道我的方法是错误的,而且我一直无法理解二进制转换等也无济于事,但我觉得我走在正确的道路上:

(b, byteorder = 'little', signed = True)

但无法找出我错在哪里。非常感谢任何解释这个概念的帮助。

This result is even more wild than the first. I know my approach is wrong... but can't work out where i'm wrong.

问题出在 字节的转换中。让我们一步步来看:

int(x, 2)

很好;我们将字符串视为整数值的 base-2 表示,并获取该整数。唯一的问题是它是 a) unsigned 和 b) big-endian。

hex(int(x,2))

这样做是创建整数的字符串表示形式,以 16 为基数,带有 0x 前缀。值得注意的是,我们想要的每个字节有两个文本字符。这已经走错路了。

您可能已经考虑过使用十六进制,因为您已经在字符串表示形式中看到 \xAB 样式转义。这是完全不同的事情。字符串 '\xAB' 包含一个字符。字符串 '0xAB' 包含四个。

从那里开始,其他一切仍然是废话。使用文本编码转换为 bytes 仅意味着文本字符 0 被替换为字节值 48(因为在 UTF-8 中它是用具有该值的单个字节编码的)。对于此数据,我们使用 UTF-8 得到的结果与我们假设纯 ASCII 得到的结果相同(因为 UTF-8 是“ASCII 透明的”并且文本中没有非 ASCII 字符)。


那么我们该怎么做呢?

我们想把第一步得到的整数转换成用来表示它的字节。正如有一个 .from_bytes class 方法允许我们从底层字节创建一个整数一样,有一个实例方法允许我们获取代表整数的字节。

因此,我们使用 .to_bytes,指定我们从二进制字符串创建 int 时假定的长度、符号和字节顺序 - 为我们提供与该字符串对应的字节。然后,我们从这些字节重新创建整数,除了现在指定正确的符号和字节顺序。 .to_bytes 让我们指定长度的原因是因为整数没有特定的长度——表示它需要最少的字节数,但您可以根据需要使用更多的字节数。 (如果你想处理带符号的值,这一点尤其重要,因为它会自动进行符号扩展。)

因此:

for i in input_data:
    values = [int(x,2) for x in i]
    as_bytes = [x.to_bytes(2, byteorder='big', signed=False) for x in values]
    reinterpreted = [int.from_bytes(x, byteorder='little', signed=True) for x in as_bytes]
    results_2.append(reinterpreted)

但让我们稍微改进一下代码的组织。我将首先创建一个函数来处理单个整数值,然后我们可以使用理解来处理列表。事实上,我们可以对嵌套列表使用嵌套理解。

def as_signed_little(binary_str):
    # This time, taking advantage of positional args and default values.
    as_bytes = int(binary_str, 2).to_bytes(2, 'big')
    return int.from_bytes(as_bytes, 'little', signed=True)

# And now we can do:
results_2 = [[as_signed_little(x) for x in i] for i in input_data]