在Python中将整数列表转换为二进制“字符串”

4

我有一个数字列表,我想将它们作为二进制数据发送到套接字连接。

举个例子,我从以下列表开始:

data = [2,25,0,0,ALPHA,0,23,18,188]

在上面的列表中,ALPHA可以是1到999之间的任何值。最初,我使用以下方式将其转换为字符串:
 hexdata = ''.join([chr(item) for item in data])

所以如果 ALPHA 是 101,这将返回以下字符串:
>>> data = [2,25,0,0,101,0,23,18,188]
>>> hexdata = ''.join([chr(item) for item in data])
>>> hexdata
'\x02\x19\x00\x00e\x00\x17\x12\xbc'

这个代码可以正常工作,'\x02\x19\x00\x00e\x00\x17\x12\xbc'是我需要发送的字符串。

但是,如果ALPHA的值超过255,这个代码就无法工作,因为它超出了chr语句的范围。例如,如果ALPHA为999,则我希望得到以下字符串:

data = [2,25,0,0,999,0,23,18,188]
hexdata = '\x02\x19\x00\x03\xed\x00\x17\x12\xbc'

我一直在查看struct.pack()的文档,但无法看出如何使用它来实现上述字符串。 ALPHA是列表中唯一的变量。
非常感谢您的任何帮助。
编辑1
你想要什么行为?256到65535之间的任何内容都需要2个字节才能表示。你想在另一端解包吗?请更新帖子并表明您的意图。 - gahooa 1分钟前
这是正确的,因为999超过了256的阈值,所以它由两个字节表示:
data = [2,25,0,0,999,0,23,18,188]

hexdata = '\x02\x19\x00**\x03\xed**\x00\x17\x12\xbc'

请问这有意义吗?

就解包而言,我只是将这些数据发送到套接字上,我会接收数据,但那已经处理好了。

编辑2

我发送的字符串长度总是固定的。为简单起见,我认为最好将列表表示如下:

ALPHA = 101

data = [25,alpha1,alpha2,1]
hexdata = '\x19\x00e\x01'


ALPHA = 301

data = [25,alpha1,alpha2,1]
hexdata = 'x19\x01\x2d\x01'

如您所见,在hexdata字符串中,它变成了:\x01\x2d\

如果ALPHA<256,则alpha1 = 0。


2
你想要什么行为?256到65535之间的任何内容都需要2个字节来表示。你想在另一侧解包它吗?请更新帖子并表明你的意图 - gahooa
'\x03\xed' 是大端字节序的 1005 的表示?你是如何得出这个结论的?同时,缺少一个 \x00 是有意为之的吗? - Ants Aasma
我强烈建议您为数据包使用固定大小的记录,这将使您的协议更简单(并且由于对齐/打包问题,大小可能保持不变)。 - tonfa
5个回答

9

如果 ALPHA 小于 256,你想发送单独一个字节,但如果大于或等于 256,则想发送两个字节?这看起来很奇怪,因为接收方如何知道是哪种情况呢?

但是,如果这确实是你想要的话,那么

x = struct.pack(4*'B' + 'HB'[ALPHA<256] + 4*'B', *data)

这是实现此目标的一种方法。

1
这导致在999的情况下结果为'\x02\x19\x00\x00\xe7\x03\x00\x17\x12\xbc'。注意两个\x00和错误的字节顺序(至少在x86机器上)。 - Ants Aasma
3
我建议使用大端序,这也是每个网络协议应该采用的方式(以避免任何出乎意料的情况)。 - tonfa
@AntsAasma - 如果字节顺序是一个问题,你可以在字符串的开头添加"<"来表示小端。例如:struct.pack("<" + 4*'B' + 'HB'[ALPHA<256] + 4*'B', *data) - Tom Leys

5
如果您事先知道数据和ALPHA位置,最好使用大端短结构体(struct.pack)来表示该位置,并省略可能被覆盖的0:
def output(ALPHA):
    data = [2,25,0,ALPHA,0,23,18,188]
    format = ">BBBHBBBB"
    return struct.pack(format, *data)
output(101) # result: '\x02\x19\x00\x00e\x00\x17\x12\xbc'
output(999) # result: '\x02\x19\x00\x03\xe7\x00\x17\x12\xbc'

3
您可以使用Python的array模块。
import array
a = array.array('i')
a.extend([2,25,0,0,101,0,23,18,188])
output = a.tostring()

2
虽然这并没有回答原始(奇怪的)变宽度 alpha 通道的要求,但对于我所需要的东西来说,这是一个很好的提示。谢谢! - natevw

1

字节的值不能超过255,因此如果ALPHA超过255,则必须将其拆分为两个字节。可以这样做:

high, low  = divmod(ALPHA, 255)

然后,您可以将高位和低位插入值列表中。

还有其他变体,例如使用bytearray(在2.6中)或struct.pack等,但最终您仍然需要以某种方式将该数字转换为两个字节。


0
你想发送一个单字节的 ALPHA,如果它小于 256,但如果大于等于 256,则发送两个字节吗?
另一种(可能更通用)的方法是:
x = reduce(lambda x, y: x + y, map(lambda x: struct.pack('B', x), data))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接