为了提供一些背景信息,我正在解析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实现这一目标?

最佳答案

简短答案

目前,只有用命令式语言编写的plugging in the code才能将Python代码准确地转录为KS本身。

但是,由于您提供了其他信息,因此可以使用一种替代方法,请参见下面的解决方案。

更长的答案

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


请告诉我我是否正确,这对您的项目有用吗?

关于python - 根据之前的元素解析项目,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43631711/

10-11 23:55
查看更多