Разбор индексов списков с конструкцией - PullRequest
0 голосов
/ 04 мая 2018

Допустим, формат файла определен так:

size (uint32)
some_list[size] (uint32)
size_indexes (uint32)
other_list[size_indexes] (uint32)

Итак, есть список some_list, содержащий некоторые целые числа, а затем есть другой список other_list, содержащий индексы в some_list.

Я могу разобрать всю структуру с помощью конструкции следующим образом:

from construct import *

fmt = Struct(
        "size" / Int32ul,
        "some_list" / Array(this.size, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / Array(this.size_indexes, Int32ul),
        )

print(fmt.parse(b"\x02\x00\x00\x00\x23\x42\x23\x42\x13\x37\x13\x37\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00"))

что дает мне

Container: 
    size = 2
    some_list = ListContainer: 
        1109606947
        924006163
    size_indexes = 4
    other_list = ListContainer: 
        1
        1
        0
        1

Теперь, когда я проанализировал формат файла, каков предпочтительный способ создания из него объекта python? Например, вместо того, чтобы other_list содержал индексы, я хотел бы, чтобы он содержал фактические значения. Не могли бы вы обернуть вокруг него другой объект, обладающий такой способностью, например, такой:

from construct import *

fmt = Struct(
        "size" / Int32ul,
        "some_list" / Array(this.size, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / Array(this.size_indexes, Int32ul),
        )


class MyFormat:
    def __init__(self, raw):
        self._parsed = fmt.parse(raw)

    @property
    def other_list(self):
        for idx in self._parsed.other_list:
            yield self._parsed.some_list[idx]



container = MyFormat(b"\x02\x00\x00\x00\x23\x42\x23\x42\x13\x37\x13\x37\x04\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00")

print(list(container.other_list))

который печатает:

[924006163, 924006163, 1109606947, 924006163]

Есть ли лучший, более предпочтительный способ?

1 Ответ

0 голосов
/ 11 октября 2018

Если код struct не слишком сложен, можно использовать классы, предоставляемые библиотекой construct. В вашем случае я бы попробовал IfThenElse и RepeatUntil классы, чтобы иметь только один struct для построения и анализа двоичных данных.

Вот пример:

import construct

def repeat_handler( x, lst, ctx):
    lst[-1] = ctx.some_list[x]
    return len(lst) == ctx.size_indexes

my_struct = Struct(
        "s" / Int32ul,
        "some_list" / Array(this.s, Int32ul),
        "size_indexes" / Int32ul,
        "other_list" / construct.IfThenElse(this._parsing,
                                            RepeatUntil(repeat_handler, construct.Int32ul),
                                            Array(this.size_indexes, Int32ul))
        )


built_struct = my_struct.build(dict(s=2, some_list=[1109606947, 924006163], size_indexes=4, other_list=[1, 1, 0, 1]))
print(built_struct)

parsed_struct = my_struct.parse(built_struct)
print(parsed_struct)

assert parsed_struct.other_list == [924006163, 924006163, 1109606947, 924006163]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...