gpt4 book ai didi

python - 如何验证 PyParsing 中动态定义的语法元素

转载 作者:行者123 更新时间:2023-11-28 16:42:11 26 4
gpt4 key购买 nike

我正在使用 PyParsing 为相当复杂的语法实现一个解析器。 (如果我可以补充的话,使用起来真的很愉快!)

语法有点“动态”,因为它允许定义(各种)字母表,这些字母表又定义了其他定义中允许的元素。例如:

alphabet: a b c
lists:
s1 = a b
s2 = b c x

此处,alphabet 用于定义lists 定义中允许的元素。例如,s1 是有效的,但 s2 包含无效的 x

没有这种验证的简单 PyParsing 解析器可能如下所示:

from pyparsing import Literal, lineEnd, Word, alphanums,\
OneOrMore, Group, Suppress, dictOf

def fixedToken(literal):
return Suppress(Literal(literal))

Element = Word(alphanums)

Alphabet = Group(OneOrMore(~lineEnd + Element))
AlphaDef = fixedToken("alphabet:") + Alphabet

ListLine = OneOrMore(~lineEnd + Element)
Lists = dictOf(Word(alphanums) + fixedToken("="), ListLine)

Start = AlphaDef + fixedToken("lists:") + Lists

if __name__ == "__main__":

data = """
alphabet: a b c
lists:
s1 = a b
s2 = b c x
"""

res = Start.parseString(data)
for k, v in sorted(res.items()):
print k, "=", v

这将解析并给出输出:

Alphabet= set(['a', 'c', 'b'])
s1 = ['a', 'b']
s2 = ['b', 'c', 'x']

但是,我希望解析器为 s2 引发 ParseException(或类似异常),因为它包含无效的 x。理想情况下,我希望能够使 ListLine 的定义类似于:OneOrMore(oneOf(Alphabet)) - 但显然,这需要一些动态解释这只能在 Alphabet 实际被解析和组装后完成。

我找到的一个解决方案是将解析操作添加到 1. 记住字母表和 2. 验证行:

# ...
Alphabet = Group(OneOrMore(~lineEnd + Element))
def alphaHold(toks):
alphaHold.alpha = set(*toks)
print "Alphabet=", alphaHold.alpha
Alphabet.addParseAction(alphaHold)

AlphaDef = fixedToken("alphabet:") + Alphabet

ListLine = OneOrMore(~lineEnd + Element)
def lineValidate(toks):
unknown = set(toks).difference(alphaHold.alpha)
if len(unknown):
msg= "Unknown element(s): {}".format(unknown)
print msg
raise ParseException(msg)
ListLine.addParseAction(lineValidate)
# ...

这几乎给出了所需的输出:

Alphabet= set(['a', 'c', 'b'])
Unknown element(s): set(['x'])
s1 = ['a', 'b']

但不幸的是,PyParsing 捕获了解析操作抛出的异常,因此这种方法在技术上失败了。在 PyParsing 中是否有另一种我可能错过的方法来实现这一点?

最佳答案

您已经非常接近这个工作了。在许多情况下,pyparsing 解析器会根据先前解析的文本动态调整自身。诀窍是使用 Forward 占位符表达式,然后将所需的值作为解析操作的一部分插入到占位符中(非常接近您现在的位置) .像这样:

Element = Forward()

Alphabet = OneOrMore(~lineEnd + oneOf(list(alphas)))
def alphaHold(toks):
Element << oneOf(toks.asList())
Alphabet.setParseAction(alphaHold)

从这里开始,我认为您的其余代码按原样运行得相当好。实际上,您甚至不需要行验证函数,因为 pyparsing 只会将有效的元素名称匹配为使用此方法的元素。

您可能会发现 pyparsing 的错误报告有点模糊。在某些明智的地方使用“-”而不是“+”可以让事情变得更好一些。由于 pyparsing 将 ParseExceptions 用于表达式匹配/不匹配的所有内部信号,因此它不会自动识别您何时进入已定义的表达式,但随后对包含的表达式进行无效匹配。您可以使用“-”运算符告诉 pyparsing 检测此问题,如下所示:

ListDef = listName + '=' - OneOrMore(~lineEnd + Element)

一旦 pyparsing 获得名称和“=”符号,则发现任何无效元素将立即引发 ParseSyntaxException,这将停止 pyparsing 在该点对文本的扫描,并报告异常无效元素的位置。

关于python - 如何验证 PyParsing 中动态定义的语法元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17946734/

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