pyparsing如何跳过缩进块的结尾?

2024-04-24 08:04:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用pyparsing来解析这样的结构:

identifier: some description text here which will wrap
    on to the next line. the follow-on text should be
    indented. it may contain identifier: and any text
    at all is allowed
next_identifier: more description, short this time
last_identifier: blah blah

我需要这样的东西:

^{pr2}$

但是我很难定义SkipTo子句的next_identifier,因为标识符可以自由地出现在描述文本中。在

似乎我需要在语法中包含缩进,这样我就可以跳过下一个没有缩进的行。在

我试过了:

description = pp.Combine(
    pp.SkipTo(pp.LineEnd()) +
    pp.indentedBlock(
        pp.ZeroOrMore(
            pp.SkipTo(pp.LineEnd())
        ),
        indent_stack
    )
)

但我得到了一个错误:

ParseException: not a subentry (at char 55), (line:2, col:1)

Char 55位于run-on-line的最开始:

...will wrap\n    on to the next line...
              ^

这看起来有点奇怪,因为char位置后面明显跟有空格,这使得它成为一个缩进的子条目。在

我在ipdb中的回溯如下:

   5311     def checkSubIndent(s,l,t):
   5312         curCol = col(l,s)
   5313         if curCol > indentStack[-1]:
   5314             indentStack.append( curCol )
   5315         else:
-> 5316             raise ParseException(s,l,"not a subentry")
   5317

ipdb> indentStack
[1]
ipdb> curCol
1

我应该补充的是,上面我匹配的整个结构也可能缩进了(以未知的量),因此解决方案如下:

description = pp.Combine(
    pp.SkipTo(pp.LineEnd()) + pp.LineEnd() +
    pp.ZeroOrMore(
        pp.White(' ') + pp.SkipTo(pp.LineEnd()) + pp.LineEnd()
    )
)

……在我的例子中,这种方法是有效的,因为它会消耗后面的定义。在


Tags: thetextonlinedescription结构willpp
1条回答
网友
1楼 · 发布于 2024-04-24 08:04:18

使用indentedBlock时,传入的参数是块中每一行的表达式,因此它不应该是indentedBlock(ZeroOrMore(line_expression), stack),而应该是indentedBlock(line_expression, stack)。Pyparsing包含一个用于“从这里到行尾的所有内容”的内置表达式,名为restOfLine,因此我们只将其用于缩进块中每一行的表达式:

import pyparsing as pp

NL = pp.LineEnd().suppress()

label = pp.ungroup(pp.Word(pp.alphas, pp.alphanums+'_') + pp.Suppress(":"))

indent_stack = [1]
# see corrected version below
#description = pp.Group((pp.Empty() 
#                    + pp.restOfLine + NL
#                    + pp.ungroup(pp.indentedBlock(pp.restOfLine, indent_stack))))

description = pp.Group(pp.restOfLine + NL
                       + pp.Optional(pp.ungroup(~pp.StringEnd() 
                                                + pp.indentedBlock(pp.restOfLine, 
                                                                   indent_stack))))

labeled_text = pp.Group(label("label") + pp.Empty() + description("description"))

我们使用ungroup删除由indentedBlock创建的额外级别的嵌套,但是我们还需要删除在indentedBlock中内部创建的每行嵌套。我们通过一个解析操作来执行此操作:

^{pr2}$

在这一点上,我们已经差不多完成了。以下是解析并转储的示例文本:

parsed_data = (pp.OneOrMore(labeled_text)).parseString(sample)    
print(parsed_data[0].dump())

['identifier', ['some description text here which will wrap', 'on to the next line. the follow-on text should be', 'indented. it may contain identifier: and any text', 'at all is allowed']]
- description: ['some description text here which will wrap', 'on to the next line. the follow-on text should be', 'indented. it may contain identifier: and any text', 'at all is allowed']
- label: 'identifier'

或使用此代码拉出“标签”和“说明”字段:

for item in parsed_data:
    print(item.label)
    print('..' + '\n..'.join(item.description))
    print()

identifier
..some description text here which will wrap
..on to the next line. the follow-on text should be
..indented. it may contain identifier: and any text
..at all is allowed

next_identifier
..more description, short this time

last_identifier
..blah blah

相关问题 更多 >