PyParsing 与嵌套语法的行为不符合预期
PyParsing not behaving as expected with nested grammar
我有一个关于嵌套语法的问题。你如何让 pyparsing 寻找嵌套的语法结构。
from pyparsing import Word, alphas, alphanums, Suppress, LineEnd, LineStart, nums, Or, Group, OneOrMore, Literal, CaselessLiteral, Combine, Optional
word = Word(alphanums+'_')
object_type = Suppress("object ")+word.setResultsName("object_type")+Suppress('{')+LineEnd()
point = Literal('.')
e = CaselessLiteral('E')
plusorminus = Literal('+') | Literal('-')
number = Word(nums)
integer = Combine( Optional(plusorminus) + number )
floatnumber = Combine( integer +
Optional( point + Optional(number) ) +
Optional( e + integer )
)
attribute = word.setResultsName("attribute")
value = Or([floatnumber, word]).setResultsName("value")
attributes = Group(attribute+value+Suppress(";")+LineEnd())
namespace = Group(object_type+\ OneOrMore(attributes).setResultsName("attributes") + Suppress("}"))
all = OneOrMore(namespace).setResultsName("namespaces")
result = all.parseString(glm)
for n in result.namespaces:
print(n)
以下是我想解析的示例。第一个命名空间按预期工作。然而,第二个无法解析。谁能解释我错过了什么?
"""object object_type1{
attr1 0.0111;
name name_of_object_1;
}
object object_type1{
attr1 0.02;
name name_of_object_2;
object object_type2{
name name_of_object_3;
}
}
"""
要定义递归语法,即具有本身是其自身定义一部分的术语的语法,您需要使用 pyparsing 的 Forward
class。在您的情况下, namespace
可以包含属性或嵌套的名称空间。为此,您首先必须为 namespace
:
定义一种占位符
namespace = Forward()
然后当需要定义内容时(包括 namespace
作为定义的一部分),使用 <<=
运算符而不是 =
:
namespace <<= Group(object_type + OneOrMore(attributes|namespace).setResultsName("attributes") + Suppress("}"))
all = OneOrMore(namespace).setResultsName("namespaces")
除此之外,您的解析器应该可以正常工作。
其他一些提示:
我最近添加了 pprint()
方法来简化列出 ParseResults 对象的内容。尝试 result.pprint()
而不是您现在使用的 for 循环。
您实际上不需要输出中的换行符,因此将所有 LineEnd()
项替换为 LineEnd().suppress()
- 这会稍微整理一下您的结果。
在这种情况下,我不确定结果名称是否真的对您有很大帮助。但我发现使用 expr("name")
比 expr.setResultsName("name")
更具可读性。但是任何一种形式都可以。
我有一个关于嵌套语法的问题。你如何让 pyparsing 寻找嵌套的语法结构。
from pyparsing import Word, alphas, alphanums, Suppress, LineEnd, LineStart, nums, Or, Group, OneOrMore, Literal, CaselessLiteral, Combine, Optional
word = Word(alphanums+'_')
object_type = Suppress("object ")+word.setResultsName("object_type")+Suppress('{')+LineEnd()
point = Literal('.')
e = CaselessLiteral('E')
plusorminus = Literal('+') | Literal('-')
number = Word(nums)
integer = Combine( Optional(plusorminus) + number )
floatnumber = Combine( integer +
Optional( point + Optional(number) ) +
Optional( e + integer )
)
attribute = word.setResultsName("attribute")
value = Or([floatnumber, word]).setResultsName("value")
attributes = Group(attribute+value+Suppress(";")+LineEnd())
namespace = Group(object_type+\ OneOrMore(attributes).setResultsName("attributes") + Suppress("}"))
all = OneOrMore(namespace).setResultsName("namespaces")
result = all.parseString(glm)
for n in result.namespaces:
print(n)
以下是我想解析的示例。第一个命名空间按预期工作。然而,第二个无法解析。谁能解释我错过了什么?
"""object object_type1{
attr1 0.0111;
name name_of_object_1;
}
object object_type1{
attr1 0.02;
name name_of_object_2;
object object_type2{
name name_of_object_3;
}
}
"""
要定义递归语法,即具有本身是其自身定义一部分的术语的语法,您需要使用 pyparsing 的 Forward
class。在您的情况下, namespace
可以包含属性或嵌套的名称空间。为此,您首先必须为 namespace
:
namespace = Forward()
然后当需要定义内容时(包括 namespace
作为定义的一部分),使用 <<=
运算符而不是 =
:
namespace <<= Group(object_type + OneOrMore(attributes|namespace).setResultsName("attributes") + Suppress("}"))
all = OneOrMore(namespace).setResultsName("namespaces")
除此之外,您的解析器应该可以正常工作。
其他一些提示:
我最近添加了
pprint()
方法来简化列出 ParseResults 对象的内容。尝试result.pprint()
而不是您现在使用的 for 循环。您实际上不需要输出中的换行符,因此将所有
LineEnd()
项替换为LineEnd().suppress()
- 这会稍微整理一下您的结果。在这种情况下,我不确定结果名称是否真的对您有很大帮助。但我发现使用
expr("name")
比expr.setResultsName("name")
更具可读性。但是任何一种形式都可以。