pyparsing捕获具有给定标题的任意文本组作为嵌套列表

时间:2012-02-20 12:58:22

标签: python pyparsing

我有一个类似于;

的文本文件
  

节标题1:
  有些词可以是任何东西   更多的话可以是任何事物   等等lala

     

其他一些标题:
  像以前一样可以是任何事物   嘿,这不是很有趣

我正在尝试用pyparser构造一个语法,当要求将解析结果作为列表时,这将导致以下列表结构; (IE;在遍历parsed.asList()元素时应该打印以下内容)

  

['标题1:',[['某些词可以是任何'],['更多的词可以是任何东西'],['etc etc lala']]]
  ['其他一些标题:',[[以前可能是任何事情],['嘿,这不是很有趣']]]

标题名称都是事先已知的,并且可能会显示或不显示各个标题。如果它们确实出现,那么至少有一行内容。

我遇到的问题是,我无法解析解析器以识别'section header 1:'ands和'some other header:'的开始位置。我最终得到了一个类似于;

的parsed.asList()
  

['标题1:',[[''有些单词可以是任何'],['更多单词可以是任何东西'],['etc etc lala'],['其他标题'] ,[''以前可能是任何事情',['嘿,这不是很有趣']]]

(IE:部分标题1:正确看到,但是后面的每个部分都被添加到部分标题1中,包括更多的标题行等等。)

我尝试了各种各样的东西,以各种方式使用leaveWhitespace()和LineEnd(),但我无法理解。

我正在讨厌的基本解析器是(人为的例子 - 实际上这是一个类定义等等。)。

header_1_line=Literal('section header 1:')

text_line=Group(OneOrMore(Word(printables)))

header_1_block=Group(header_1_line+Group(OneOrMore(text_line)))

header_2_line=Literal('some other header:')

header_2_block=Group(header_2_line+Group(OneOrMore(text_line)))

overall_structure=ZeroOrMore(header_1_block|header_2_block)

正在调用

parsed=overall_structure.parseFile()

干杯,马特。

1 个答案:

答案 0 :(得分:12)

马特 -

欢迎来到pyparsing!你已经陷入了与pyparsing合作最常见的陷阱之一,那就是人们比计算机更聪明。当您查看输入文本时,您可以轻松查看哪些文本可以是标题,哪些文本不可以。不幸的是,pyparsing不是那么直观,所以你必须明确地告诉它可以是什么,不能是文本。

当您查看示例文本时,您仅接受任何文本行作为节标题中的可能文本。你怎么知道“其他一些标题:”作为文本无效?因为您知道该字符串与其中一个已知的标题字符串匹配。但是在您当前的代码中,您告诉pyparsing Word(printables)的任何集合都是有效文本,即使该集合是有效的节标题

要解决此问题,您必须向解析器添加一些明确的前瞻。 Pyparsing提供两种结构,NotAny和FollowedBy。 NotAny可以使用'〜'运算符缩写,因此我们可以为文本编写这个伪代码表达式:

text = ~any_section_header + everything_up_to_the_end_of_the_line

这是一个使用负向前瞻的完整解析器,以确保您阅读每个部分,打破部分标题:

from pyparsing import ParserElement, LineEnd, Literal, restOfLine, ZeroOrMore, Group, StringEnd

test = """
section header 1:
 some words can be anything
 more words could be anything at all
 etc etc lala 

some other header:
 as before could be anything
 hey isnt this fun
"""
ParserElement.defaultWhitespaceChars=(" \t")
NL = LineEnd().suppress()
END = StringEnd()

header_1=Literal('section header 1:') 
header_2=Literal('some other header:')
any_header = (header_1 | header_2)
# text isn't just anything! don't accept header line, and stop at the end of the input string
text=Group(~any_header + ~END + restOfLine) 

overall_structure = ZeroOrMore(Group(any_header +
                                     Group(ZeroOrMore(text))))
overall_structure.ignore(NL)

from pprint import pprint
print(overall_structure.parseString(test).asList())

在我的第一次尝试中,我忘了也寻找字符串的结尾,所以我的restOfLine表达式永远循环。通过为字符串结尾添加第二个前瞻,我的程序成功终止。为您留下的练习:不是枚举所有可能的标题,而是将标题行定义为以“:”结尾的任何行。

祝你的pyparsing努力好运, - 保罗