pyparsing:问题与给定列表的单词(CaselessLiteral)之一匹配

时间:2018-11-22 14:55:40

标签: python-3.x parsing pyparsing

我正在用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形式给出的呢?

非常感谢您的帮助!

干杯, 波城

1 个答案:

答案 0 :(得分:0)

感谢您分享一个有趣的问题。抱歉,我没有适合您的“好”解决方案。 (也许如果您花一点时间将其煮沸成一个更简单的“重复”,一个显示出相同效果的更简单的语法?)

我将提供这个建议。考虑进行预处理,以便(A.)带有'&'的连续行成为单个长行,更重要的是(B.)每行基于诸如“ FL2EXTR”或“ CSRCSBEN”之类的字符串而获得类型前缀。称它们为{TYPE1,TYPE2}或任何方便的名称,并将该标记放在行首。

现在,您将面临一对更简单的问题,编写一对简单的语法,这些语法要处理的细节更少。初始类型标记应使更容易根据需要触发第一或第二语法产生。