我有一个类似于;
的文本文件节标题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()
干杯,马特。
答案 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努力好运, - 保罗