【问题标题】:Parse an item depending on previous elements根据先前的元素解析项目
【发布时间】:2017-04-26 20:02:24
【问题描述】:

为了提供一些上下文,我正在解析一个 DICOM 文件,并且在使用 Transfer Syntax 条目来确定是使用隐式解析还是显式解析时遇到了困难。但是让我定义一个简化的语法,所以不需要 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 实现这一点?

【问题讨论】:

    标签: python parsing kaitai-struct


    【解决方案1】:

    简答

    目前不可能将 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
    

    请告诉我我是否做对了,这是否适用于您的项目?

    【讨论】:

    • 谢谢,这看起来很有希望!出于某种原因,我一直在寻找一种方法来重复直到第一个非 2 组条目,但这没有帮助。在我接受你的回答之前,让我先把它应用到我的现实世界场景中。
    • 我不得不发现如果 is_u4 从未设置过,这不起作用,因为流的结尾被命中并生成异常。是否有repeat: until or eos 选项或类似的选项?
    • 试试repeat-until: _.is_u4 or _io.eof
    猜你喜欢
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 2021-12-29
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    相关资源
    最近更新 更多