根据以前的元素解析项目

时间:2017-04-26 10:34:10

标签: python parsing kaitai-struct

为了给出一些上下文,我正在解析DICOM文件,并且难以使用传输语法条目来确定是使用隐式还是显式解析。但是,让我定义一个简化的语法,因此不需要dicom知识。

我们有一系列条目,每个条目都有一个group number和一个data部分。组号始终表示为u2,但数据可以是不同类型,例如u2u4。条目的顺序可以是任意的,除了group number == 2的所有条目必须位于顶部。 group number == 2的所有条目的数据类型均为u2,但后续数据部分可能不同。

这里有困难的部分:group number != 2的所有项目都有数据类型u4当且仅当之前存在与此类似的条目时才会出现:

(group, data) == (0x0002, 0x0101)

在python中,我会像这样解析它:

def read_entries(stream):
  is_u4 = False
  while not stream.eos():
    group = stream.read_u2()
    if group != 2 and is_u4:
      data = stream.read_u4()
    else:      
      data = stream.read_u2()
    if group == 2 and data == 0x0101:
      is_u4 = True
    yield (group, data)

有没有办法用kaitai-struct实现这个目标?

1 个答案:

答案 0 :(得分:3)

简短回答

现在不可能将Python代码精确转录到KS本身,只能用命令式语言编写plugging in the code

但是,由于您的其他信息,可以使用其他方法,请参阅下面的解决方案。

更长的答案

Kaitai Struct强调无状态解析,因此我们解析的所有内容实际上都是不可变的(只读),即有些变量可以在解析过程中改变其值。因此,在解析周期之间传播is_u4是非常重要的事情。例如,我们遇到与MIDI running status类似的问题。

人们建议的一些解决方案有时是使用_parent语法的递归类型定义+实例传播(参见issue #70),但是:

  • 由于缺少递归定义的实例值的类型定义+缺少初始值播种,目前阻碍了
  • 这会生成一个值的链接列表,而不是一个数组(即大多数人都不熟悉的那个)
  • 这会对调用堆栈造成沉重的负担(即,可疑的长结构很可能会因堆栈耗尽而失败)

替代方法,鉴于您提供的其他信息可能是可行的。实际上,事实证明,整个元素流可以分为3组:

  • 之前的元素(0x0002,0x0101) - 它们都使用u2-u2格式
  • (0x0002,0x0101)元素本身 - 请注意,当它第一次遇到时它也总是u2-u2
  • 后面的元素(0x0002,0x0101) - 它们都使用u2-u4格式;即使之后遇到额外的(0x0002,0x0101),根据你提供的算法,它应该被读作u2-u4,所以没关系。

因此可以逃脱:

types:
  elements:
    seq:
      - id: elements_2
        type: element_2
        repeat-until: _.is_u4
      - id: elements_4
        type: element_4
        repeat: eos
  element_2:
    seq:
      - id: group
        type: u2
      - id: data
        type: u2
    instances:
      is_u4:
        value: group == 2 and data == 0x0101
  element_4:
    seq:
      - id: group
        type: u2
      - id: data
        type: u4

请告诉我,如果我做对了,那对你的项目有用吗?