我正在用pyparsing为特定文件结构编写一个解析器。它主要是元素定义的列表,其语法为: ElementName:ElementType,ParameterList 。 ParameterList 是可选的,具有pp.delimitedList的结构。此文件的示例摘录如下:
"L_000333": DRIF,L=0.0607
BPM15FL2EXTR: MONI
Q8FL2EXTR: QUAD, &
L=0.3286,K1=-0.7494081,&
DY="vert_offset_1"
"L_000334": DRIF,L=0.359694
D8FL2EXTR: CSRCSBEN,L=0.2200112619037261, &
ANGLE=-0.015708,E1=-0.007854, E2=-0.007854, &
SG_HALFWIDTH = 1, DY = "vert_offset_1", &
N_KICKS = "num_CSR_kicks", BINS = "bin_num", &
ISR = "with_ISR", CSR = "with_CSR", &
OUTPUT_INTERVAL = "output_interval", &
INTEGRATION_ORDER = "order_integration"
"L_000335": DRIF,L=0.134994
V9FL2EXTR: VKICK,L=0.1
...
要匹配 ElementType ,我想使用给定选项的列表,因为有一个名为LINE的特殊类型,它与上面示例中给出的结构定义不匹配。线。例如,LINE类型遵循以下语法:
FL2EXTR: LINE=(STARTFLEXTR,L_000297,FSHUTTER, ... etc... )
,可以在上面给出的元素之间找到。但是到现在为止,我将忘记如何解析这种特殊类型的元素,因为问题出在:-/。
为了正确解析给定的元素列表,我定义了以下构建块:
import pyparsing as pp
# allowed delimiters:
lte_delim_0 = pp.Literal(',')
lte_delim_1 = pp.Literal('&')
lte_delim_2 = pp.Literal(',') + lte_delim_1
lte_delim = pp.Or([lte_delim_0, lte_delim_1, lte_delim_2])
# ElementName:
elementName = pp.Or([pp.Word(pp.alphanums + '_'), pp.dblQuotedString]) + \
pp.Literal(':').suppress()
# ElementType:
elementType = pp.Or([pp.CaselessLiteral('DRIF'),
pp.CaselessLiteral('ALPH'),
pp.CaselessLiteral('BGGEXP'),
pp.CaselessLiteral('BMAPXY'),
pp.CaselessLiteral('BMXYZ'),
... looong list of possible ElementType ...
pp.CaselessLiteral('ZTRANSVERSE')])
# ParameterName and ParameterValue for the ParameterList:
parameterName = pp.Word(pp.alphanums + '_')
parameterValue = pp.Or([pp.Word(pp.alphanums + '_'),
pp.pyparsing_common.number,
pp.dblQuotedString])
# basic assignment definition:
assignmentExpr = pp.Group(parameterName('ParameterName') + \
pp.Literal('=').suppress() + \
parameterValue('ParameterValue'))
parameterList = pp.Dict(pp.delimitedList(assignmentExpr,
delim = lte_delim, combine = False))
# element definition
elementDefinition = pp.Group(elementName('ElementName') + \
elementType('ElementType') + \
pp.Optional(lte_delim.suppress() + \
parameterList('ParameterList')))
然后我为元素列表创建一个解析器,如下:
elementList = pp.OneOrMore(ElementDefinition)
但是,当我解析上面给出的示例列表时,解析器遇到元素CSRCSBEN时将停止解析(即使它在可能的pp.CaselessLiterals的elementType列表中定义了!)。
如果不是像我上面那样用pp.Or([... pp.CaselessLiterals ...]的列表来定义elementType解析器,我会简单地将elementType定义为:
elementType = pp.Word(pp.alphanums + '_')
然后我就正确解析了列表中的所有元素定义。但是然后,我无法通过不同的解析来实现特定的ElementType'LINE'...
有人可以帮我吗?为什么解析器会在元素CSRCSBEN处停止,即使它是以有效的ElementType形式给出的呢?
非常感谢您的帮助!
干杯, 波城
答案 0 :(得分:0)
感谢您分享一个有趣的问题。抱歉,我没有适合您的“好”解决方案。 (也许如果您花一点时间将其煮沸成一个更简单的“重复”,一个显示出相同效果的更简单的语法?)
我将提供这个建议。考虑进行预处理,以便(A.)带有'&'的连续行成为单个长行,更重要的是(B.)每行基于诸如“ FL2EXTR”或“ CSRCSBEN”之类的字符串而获得类型前缀。称它们为{TYPE1,TYPE2}或任何方便的名称,并将该标记放在行首。
现在,您将面临一对更简单的问题,编写一对简单的语法,这些语法要处理的细节更少。初始类型标记应使更容易根据需要触发第一或第二语法产生。