在php中,unpack()具有“*”标志,表示“重复此格式直到输入结束”。例如,这会打印97,98,99
$str = "abc";
$b = unpack("c*", $str);
print_r($b);
python中有这样的东西吗?当然,我可以做到
str = "abc"
print struct.unpack("b" * len(str), str)
但我想知道是否有更好的方法。
答案 0 :(得分:3)
struct.unpack
中没有内置设施,但可以定义这样的功能:
import struct
def unpack(fmt, astr):
"""
Return struct.unpack(fmt, astr) with the optional single * in fmt replaced with
the appropriate number, given the length of astr.
"""
# http://stackoverflow.com/a/7867892/190597
try:
return struct.unpack(fmt, astr)
except struct.error:
flen = struct.calcsize(fmt.replace('*', ''))
alen = len(astr)
idx = fmt.find('*')
before_char = fmt[idx-1]
n = (alen-flen)/struct.calcsize(before_char)+1
fmt = ''.join((fmt[:idx-1], str(n), before_char, fmt[idx+1:]))
return struct.unpack(fmt, astr)
print(unpack('b*','abc'))
# (97, 98, 99)
答案 1 :(得分:1)
在Python 3.4及更高版本中,您可以使用新功能struct.iter_unpack
。
struct.iter_unpack(fmt, buffer)
根据格式字符串fmt从缓冲区缓冲区中迭代解压缩。此函数返回一个迭代器,它将从缓冲区读取大小相同的块,直到其所有内容都被消耗掉。缓冲区的大小(以字节为单位)必须是格式所需大小的倍数,如calcsize()所示。
每次迭代都会产生格式字符串指定的元组。
让我们说我们想用重复格式字符串b'\x01\x02\x03'*3
解包数组'<2sc'
(2个字符后跟一个字符,重复直到完成)。
使用iter_unpack
,您可以执行以下操作:
>>> import struct
>>> some_bytes = b'\x01\x02\x03'*3
>>> fmt = '<2sc'
>>>
>>> tuple(struct.iter_unpack(fmt, some_bytes))
((b'\x01\x02', b'\x03'), (b'\x01\x02', b'\x03'), (b'\x01\x02', b'\x03'))
如果要取消嵌套此结果,可以使用itertools.chain.from_iterable
。
>>> from itertools import chain
>>> tuple(chain.from_iterable(struct.iter_unpack(fmt, some_bytes)))
(b'\x01\x02', b'\x03', b'\x01\x02', b'\x03', b'\x01\x02', b'\x03')
当然,您可以使用嵌套理解来做同样的事情。
>>> tuple(x for subtuple in struct.iter_unpack(fmt, some_bytes) for x in subtuple)
(b'\x01\x02', b'\x03', b'\x01\x02', b'\x03', b'\x01\x02', b'\x03')