4

phpでは、unpack()に「*」フラグがあります。これは「入力が終了するまでこの形式を繰り返す」ことを意味します。たとえば、これは97、98、99を出力します

$str = "abc";
$b = unpack("c*", $str);
print_r($b);

Pythonにこのようなものはありますか?もちろんできます

str = "abc"
print struct.unpack("b" * len(str), str)

しかし、もっと良い方法があるかどうか疑問に思っています。

4

2 に答える 2

5

Python 3.4以降では、新しい関数を使用できますstruct.iter_unpack

struct.iter_unpack(fmt, buffer)

フォーマット文字列fmtに従って、バッファバッファから繰り返し解凍します。この関数は、すべてのコンテンツが消費されるまで、バッファーから同じサイズのチャンクを読み取るイテレーターを返します。バイト単位のバッファのサイズは、calcsize()に反映されているように、フォーマットに必要なサイズの倍数である必要があります。

各反復は、フォーマット文字列で指定されたタプルを生成します。

b'\x01\x02\x03'*3繰り返しフォーマット文字列'<2sc'(2文字の後に1文字が続く、完了するまで繰り返す)を使用して配列を解凍するとします。

を使用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')
于 2018-04-19T17:39:13.117 に答える
4

にそのような機能は組み込まれていませんが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)
于 2011-10-23T17:37:54.403 に答える