gpt4 book ai didi

python - 如何使用pyparsing LineStart?

转载 作者:太空宇宙 更新时间:2023-11-04 03:05:20 24 4
gpt4 key购买 nike

我正在尝试使用 pyparsing 从文档中的评论中解析键值对。一个键从一行的开头开始,然后是一个值。值可以在以空格开头的多行上继续。

import pyparsing as pp

instring = """
-- This is (a) #%^& comment

/*
name1: val
name2: val2 with $*&#@) junk
name3: val3: with @)(*% multi-
line: content
*/
"""

comment1 = pp.Literal("--") + pp.originalTextFor(pp.SkipTo(pp.LineEnd())).setDebug()
identifier = pp.Word(pp.alphanums + "_").setDebug()
meta1 = pp.LineStart() + identifier + pp.Literal(":") + pp.SkipTo(pp.LineEnd())
meta2 = pp.LineStart() + pp.White() + pp.SkipTo(pp.LineEnd())
metaval = meta1 + pp.ZeroOrMore(meta2)
metalist = pp.ZeroOrMore(comment1) + pp.Literal("/*") + pp.OneOrMore(metaval) + pp.Literal("*/")

if __name__ == "__main__":
p = metalist.parseString(instring)
print(p)

失败:

Matched {Empty SkipTo:(LineEnd) Empty} -> ['This is (a) #%^& comment']

File "C:\Users\user\py3\lib\site-packages\pyparsing.py", line 2305, in parseImpl
raise ParseException(instring, loc, self.errmsg, self)
pyparsing.ParseException: Expected start of line (at char 32), (line:4, col:1)

pyparsing whitespace match issues 的答案说

LineStart has always been difficult to work with, but ...

如果解析器位于第 4 行第 1 列(第一个键值对),那么为什么它找不到行首?识别以无空格开头的行和以空格开头的行的正确 pyparsing 语法是什么?

最佳答案

我认为我对 LineStart 的困惑是,对于 LineEnd,我可以寻找一个 '\n' 字符,但是LineStart 没有单独的字符。所以在 LineStart 中,我查看当前解析器位置是否正好位于 '\n' 之后;或者,如果它当前 '\n' 上,请越过它并继续。不幸的是,我在一个弄乱了报告位置的地方实现了这个,所以你会得到那些奇怪的错误,比如“无法在第 X 列 1 行上找到行的开头”,这听起来确实应该是一个成功匹配的一行的开始。另外,我想我需要重新审视这种隐式的换行跳过,或者就此而言,LineStart 的所有空格跳过。

现在,我已经通过稍微扩展您的行起始表达式来让您的代码正常工作,如:

LS = pp.Optional(pp.LineEnd()) + pp.LineStart()

并用 LS 替换了 meta1 和 meta2 中的 LineStart 引用:

comment1 = pp.Literal("--") + pp.originalTextFor(pp.SkipTo(pp.LineEnd())).setDebug()
identifier = pp.Word(pp.alphanums + "_").setDebug()
meta1 = LS + identifier + pp.Literal(":") + pp.SkipTo(pp.LineEnd())
meta2 = LS + pp.White() + pp.SkipTo(pp.LineEnd())
metaval = meta1 + pp.ZeroOrMore(meta2)
metalist = pp.ZeroOrMore(comment1) + pp.Literal("/*") + pp.OneOrMore(metaval) + pp.Literal("*/")

如果 LineStart 的这种情况让您感到不舒服,您可以尝试另一种策略:使用解析时条件仅接受从第 1 列开始的标识符:

comment1 = pp.Literal("--") + pp.originalTextFor(pp.SkipTo(pp.LineEnd())).setDebug()

identifier = pp.Word(pp.alphanums + "_").setName("identifier")
identifier.addCondition(lambda instring,loc,toks: pp.col(loc,instring) == 1)

meta1 = identifier + pp.Literal(":") + pp.SkipTo(pp.LineEnd()).setDebug()
meta2 = pp.White().setDebug() + pp.SkipTo(pp.LineEnd()).setDebug()
metaval = meta1 + pp.ZeroOrMore(meta2, stopOn=pp.Literal('*/'))
metalist = pp.ZeroOrMore(comment1) + pp.Literal("/*") + pp.LineEnd() + pp.OneOrMore(metaval) + pp.Literal("*/")

此代码完全取消了 LineStart,同时我弄清楚了我想要这个特定标记做什么。我还必须修改 metaval 中的 ZeroOrMore 重复,这样 */ 就不会被意外处理为连续的评论内容。

感谢您对此的耐心等待——我不想快速推出一个修补过的 LineStart 更改,然后发现我忽略了其他兼容性或其他边缘情况,这些情况只会让我回到当前状态这门课的状态不太好。但在发布 2.1.10 之前,我会努力澄清这种行为。

关于python - 如何使用pyparsing LineStart?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39642432/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com