为了提供一些上下文,我正在解析 DICOM 文件,并且在使用传输语法条目来确定是使用隐式解析还是显式解析时遇到困难。但让我定义一个简化的语法,这样就不需要 dicom 知识。
我们有一系列条目,每个条目都有一个组号
和一个数据
部分。组编号始终表示为 u2
,但数据可以是不同类型,例如 u2
或 u4
。条目的顺序可以是任意的,但所有组号== 2
的条目必须位于顶部。所有组编号== 2
的条目的数据类型为u2
,但后续数据部分可能不同。
困难的部分来了:当且仅当之前存在与此完全相同的条目时,组编号 != 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 代码精确转录为 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
请告诉我我的做法是否正确并且适用于您的项目?
关于python - 根据先前的元素解析项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43631711/