如何从 pyparsing Forward 对象中获取结果?
How to get results from pyparsing Forward object?
让我们假设我们有以下字符串
string = """
object obj1{
attr1 value1;
object obj2 {
attr2 value2;
}
}
object obj3{
attr3 value3;
attr4 value4;
}
"""
有一个嵌套对象,我们使用Forward来解析它。
from pyparsing import *
word = Word(alphanums)
attribute = word.setResultsName("name")
value = word.setResultsName("value")
object_grammar = Forward()
attributes = attribute + value + Suppress(";") + LineEnd().suppress()
object_type = Suppress("object ") + word.setResultsName("object_type") + Suppress('{') + LineEnd().suppress()
object_grammar <<= object_type+\
OneOrMore(attributes|object_grammar) + Suppress("}") | Suppress("};")
for i, (obj, _, _) in enumerate(object_grammar.scanString(string)):
print('\n')
print('Enumerating over object {}'.format(i))
print('\n')
print('This is the object type {}'.format(obj.object_type))
print(obj.asXML())
print(obj.asDict())
print(obj.asList())
print(obj)
print(obj.dump())
这些是结果。 obj.asXML() 函数包含所有信息,但是由于它已被展平,因此信息的顺序对于解析结果至关重要。这是最好的方法吗?我肯定错过了什么。我想要一个适用于嵌套和非嵌套对象的解决方案,即适用于 obj1、obj2 和 obj3。
此外,setResultsName('object_type')
不会 return 父对象的 object_type
。上面程序的输出如下所示。有什么建议吗?
Enumerating over object 0
This is the object type obj2
<ITEM>
<object_type>obj1</object_type>
<name>attr1</name>
<value>value1</value>
<object_type>obj2</object_type>
<name>attr2</name>
<value>value2</value>
</ITEM>
{'object_type': 'obj2', 'name': 'attr2', 'value': 'value2'}
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
- name: attr2
- object_type: obj2
- value: value2
Enumerating over object 1
This is the object type obj3
<ITEM>
<object_type>obj3</object_type>
<name>attr3</name>
<value>value3</value>
<name>attr4</name>
<value>value4</value>
</ITEM>
{'object_type': 'obj3', 'name': 'attr4', 'value': 'value4'}
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
- name: attr4
- object_type: obj3
- value: value4
我可以通过在 setResultsNames 函数中使用 listAllMatches=True
来解决这个问题。这给了我 asXML() 结果,它具有我可以从中检索信息的结构。它仍然依赖于 XML 的顺序,并且需要使用 zip 将 name
和 value
一起用于 attribute
。我会留下这个问题,看看我是否有更好的方法。
在您成功处理输入字符串后,让我对您的语法提出一些改进建议。
定义递归语法时,通常希望在输出结果中保持某种结构。在您的情况下,结构的逻辑部分是每个对象的内容,它被左大括号和右大括号包围。概念上:
object_content = '{' + ZeroOrMore(attribute_defn | object_defn) + '}'
那么支持的表达式就是(仍然是概念上的):
attribute_defn = identifier + attribute_value + ';'
object_defn = 'object' + identifier + object_content
实际的 Python/pyparsing 看起来像:
LBRACE,RBRACE,SEMI = map(Suppress, "{};")
word = Word(alphas, alphanums)
attribute = word
# expand to include other values if desired, such as ints, reals, strings, etc.
attribute_value = word
attributeDefn = Group(word("name") + value("value") + SEMI)
OBJECT = Keyword("object")
object_header = OBJECT + word("object_name")
object_grammar = Forward()
object_body = Group(LBRACE
+ ZeroOrMore(object_grammar | attributeDefn)
+ RBRACE)
object_grammar <<= Group(object_header + object_body("object_content"))
Group
为我们做了两件事:将结果构造为子对象;并且它使一个级别的结果名称不会踩到不同级别的结果名称(因此不需要 listAllMatches
)。
现在您可以使用 OneOrMore
:
来处理您的输入,而不是 scanString
print(OneOrMore(object_grammar).parseString(string).dump())
给予:
[['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]], ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]]
[0]:
['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]]
- object_content: [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]
[0]:
['attr1', 'value1']
- name: attr1
- value: value1
[1]:
['object', 'obj2', [['attr2', 'value2']]]
- object_content: [['attr2', 'value2']]
[0]:
['attr2', 'value2']
- name: attr2
- value: value2
- object_name: obj2
- object_name: obj1
[1]:
['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]
- object_content: [['attr3', 'value3'], ['attr4', 'value4']]
[0]:
['attr3', 'value3']
- name: attr3
- value: value3
[1]:
['attr4', 'value4']
- name: attr4
- value: value4
- object_name: obj3
我开始只是对您的代码进行简单的更改,但您的原始代码存在致命缺陷。您的解析器将左大括号和右大括号分成两个单独的表达式 - 而这 "works",它无法定义结果的组结构。
让我们假设我们有以下字符串
string = """
object obj1{
attr1 value1;
object obj2 {
attr2 value2;
}
}
object obj3{
attr3 value3;
attr4 value4;
}
"""
有一个嵌套对象,我们使用Forward来解析它。
from pyparsing import *
word = Word(alphanums)
attribute = word.setResultsName("name")
value = word.setResultsName("value")
object_grammar = Forward()
attributes = attribute + value + Suppress(";") + LineEnd().suppress()
object_type = Suppress("object ") + word.setResultsName("object_type") + Suppress('{') + LineEnd().suppress()
object_grammar <<= object_type+\
OneOrMore(attributes|object_grammar) + Suppress("}") | Suppress("};")
for i, (obj, _, _) in enumerate(object_grammar.scanString(string)):
print('\n')
print('Enumerating over object {}'.format(i))
print('\n')
print('This is the object type {}'.format(obj.object_type))
print(obj.asXML())
print(obj.asDict())
print(obj.asList())
print(obj)
print(obj.dump())
这些是结果。 obj.asXML() 函数包含所有信息,但是由于它已被展平,因此信息的顺序对于解析结果至关重要。这是最好的方法吗?我肯定错过了什么。我想要一个适用于嵌套和非嵌套对象的解决方案,即适用于 obj1、obj2 和 obj3。
此外,setResultsName('object_type')
不会 return 父对象的 object_type
。上面程序的输出如下所示。有什么建议吗?
Enumerating over object 0
This is the object type obj2
<ITEM>
<object_type>obj1</object_type>
<name>attr1</name>
<value>value1</value>
<object_type>obj2</object_type>
<name>attr2</name>
<value>value2</value>
</ITEM>
{'object_type': 'obj2', 'name': 'attr2', 'value': 'value2'}
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2']
- name: attr2
- object_type: obj2
- value: value2
Enumerating over object 1
This is the object type obj3
<ITEM>
<object_type>obj3</object_type>
<name>attr3</name>
<value>value3</value>
<name>attr4</name>
<value>value4</value>
</ITEM>
{'object_type': 'obj3', 'name': 'attr4', 'value': 'value4'}
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
['obj3', 'attr3', 'value3', 'attr4', 'value4']
- name: attr4
- object_type: obj3
- value: value4
我可以通过在 setResultsNames 函数中使用 listAllMatches=True
来解决这个问题。这给了我 asXML() 结果,它具有我可以从中检索信息的结构。它仍然依赖于 XML 的顺序,并且需要使用 zip 将 name
和 value
一起用于 attribute
。我会留下这个问题,看看我是否有更好的方法。
在您成功处理输入字符串后,让我对您的语法提出一些改进建议。
定义递归语法时,通常希望在输出结果中保持某种结构。在您的情况下,结构的逻辑部分是每个对象的内容,它被左大括号和右大括号包围。概念上:
object_content = '{' + ZeroOrMore(attribute_defn | object_defn) + '}'
那么支持的表达式就是(仍然是概念上的):
attribute_defn = identifier + attribute_value + ';'
object_defn = 'object' + identifier + object_content
实际的 Python/pyparsing 看起来像:
LBRACE,RBRACE,SEMI = map(Suppress, "{};")
word = Word(alphas, alphanums)
attribute = word
# expand to include other values if desired, such as ints, reals, strings, etc.
attribute_value = word
attributeDefn = Group(word("name") + value("value") + SEMI)
OBJECT = Keyword("object")
object_header = OBJECT + word("object_name")
object_grammar = Forward()
object_body = Group(LBRACE
+ ZeroOrMore(object_grammar | attributeDefn)
+ RBRACE)
object_grammar <<= Group(object_header + object_body("object_content"))
Group
为我们做了两件事:将结果构造为子对象;并且它使一个级别的结果名称不会踩到不同级别的结果名称(因此不需要 listAllMatches
)。
现在您可以使用 OneOrMore
:
scanString
print(OneOrMore(object_grammar).parseString(string).dump())
给予:
[['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]], ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]]
[0]:
['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]]
- object_content: [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]
[0]:
['attr1', 'value1']
- name: attr1
- value: value1
[1]:
['object', 'obj2', [['attr2', 'value2']]]
- object_content: [['attr2', 'value2']]
[0]:
['attr2', 'value2']
- name: attr2
- value: value2
- object_name: obj2
- object_name: obj1
[1]:
['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]
- object_content: [['attr3', 'value3'], ['attr4', 'value4']]
[0]:
['attr3', 'value3']
- name: attr3
- value: value3
[1]:
['attr4', 'value4']
- name: attr4
- value: value4
- object_name: obj3
我开始只是对您的代码进行简单的更改,但您的原始代码存在致命缺陷。您的解析器将左大括号和右大括号分成两个单独的表达式 - 而这 "works",它无法定义结果的组结构。