我想使用分隔符解析标记/值描述:和·
例如,输入为:
Name:Test•Title: Test•Keywords: A,B,C
预期结果应为名称值dict
{
"name": "Test",
"title": "Title",
"keywords: "A,B,C"
}
可能已经将"A,B,C"中的关键字拆分为一个列表。(这是一个小细节,因为Python内置的字符串的split方法会很乐意这样做)。
同时应用Map
keys={
"Name": "name",
"Title": "title",
"Keywords": "keywords",
}
因为名称和Dict关键字之间的Map将是有帮助的,但是可以是单独的步骤。
我尝试了https://trinket.io/python3/8dbbc783c7下面的代码
# pyparsing named values
# Wolfgang Fahl
# 2023-01-28 for Stackoverflow question
import pyparsing as pp
notes_text="Name:Test•Title: Test•Keywords: A,B,C"
keys={
"Name": "name",
"Titel": "title",
"Keywords": "keywords",
}
keywords=list(keys.keys())
runDelim="•"
name_values_grammar=pp.delimited_list(
pp.oneOf(keywords,as_keyword=True).setResultsName("key",list_all_matches=True)
+":"+pp.Suppress(pp.Optional(pp.White()))
+pp.delimited_list(
pp.OneOrMore(pp.Word(pp.printables+" ", exclude_chars=",:"))
,delim=",")("value")
,delim=runDelim).setResultsName("tag", list_all_matches=True)
results=name_values_grammar.parseString(notes_text)
print(results.dump())
和它的变体,但我甚至没有接近预期的结果。目前转储显示:
['Name', ':', 'Test']
- key: 'Name'
- tag: [['Name', ':', 'Test']]
[0]:
['Name', ':', 'Test']
- value: ['Test']
似乎我不知道如何定义语法和工作的分析结果的方式来获得所需的dict结果。
我的主要问题是:
- 我应该使用解析操作吗?
- 如何命名零件结果?
- 如何导航生成的树?
- 如何从delimitedList中取回列表?
- list_all_matches = True实现了什么-它的行为似乎很奇怪
我在stackoverflow上搜索了上述问题的答案,但我找不到一个一致的解决方案。
- Pyparsing delimited list only returns first element
- Finding lists of elements within a string using Pyparsing
PyParsing看起来是一个很棒的工具,但是我发现它非常不直观。幸运的是,这里有很多答案,所以我希望学习如何让这个例子工作
我自己尝试了一种循序渐进的方法:
首先,我检查了delimitedList行为,请参见https://trinket.io/python3/25e60884eb
# Try out pyparsing delimitedList
# WF 2023-01-28
from pyparsing import printables, OneOrMore, Word, delimitedList
notes_text="A,B,C"
comma_separated_values=delimitedList(Word(printables+" ", exclude_chars=",:"),delim=",")("clist")
grammar = comma_separated_values
result=grammar.parseString(notes_text)
print(f"result:{result}")
print(f"dump:{result.dump()}")
print(f"asDict:{result.asDict()}")
print(f"asList:{result.asList()}")
其返回
result:['A', 'B', 'C']
dump:['A', 'B', 'C']
- clist: ['A', 'B', 'C']
asDict:{'clist': ['A', 'B', 'C']}
asList:['A', 'B', 'C']
这看起来很有希望,关键的成功因素似乎是用"clist"命名这个列表,默认行为看起来很好。
https://trinket.io/python3/bc2517e25a更详细地显示了问题所在。
# Try out pyparsing delimitedList
# see https://stackoverflow.com/q/75266188/1497139
# WF 2023-01-28
from pyparsing import printables, oneOf, OneOrMore,Optional, ParseResults, Suppress,White, Word, delimitedList
def show_result(title:str,result:ParseResults):
"""
show pyparsing result details
Args:
result(ParseResults)
"""
print(f"result for {title}:")
print(f" result:{result}")
print(f" dump:{result.dump()}")
print(f" asDict:{result.asDict()}")
print(f" asList:{result.asList()}")
# asXML is deprecated and doesn't work any more
# print(f"asXML:{result.asXML()}")
notes_text="Name:Test•Title: Test•Keywords: A,B,C"
comma_text="A,B,C"
keys={
"Name": "name",
"Titel": "title",
"Keywords": "keywords",
}
keywords=list(keys.keys())
runDelim="•"
comma_separated_values=delimitedList(Word(printables+" ", exclude_chars=",:"),delim=",")("clist")
cresult=comma_separated_values.parseString(comma_text)
show_result("comma separated values",cresult)
grammar=delimitedList(
oneOf(keywords,as_keyword=True)
+Suppress(":"+Optional(White()))
+comma_separated_values
,delim=runDelim
)("namevalues")
nresult=grammar.parseString(notes_text)
show_result("name value list",nresult)
#ogrammar=OneOrMore(
# oneOf(keywords,as_keyword=True)
# +Suppress(":"+Optional(White()))
# +comma_separated_values
#)
#oresult=grammar.parseString(notes_text)
#show_result("name value list with OneOf",nresult)
输出:
result for comma separated values:
result:['A', 'B', 'C']
dump:['A', 'B', 'C']
- clist: ['A', 'B', 'C']
asDict:{'clist': ['A', 'B', 'C']}
asList:['A', 'B', 'C']
result for name value list:
result:['Name', 'Test']
dump:['Name', 'Test']
- clist: ['Test']
- namevalues: ['Name', 'Test']
asDict:{'clist': ['Test'], 'namevalues': ['Name', 'Test']}
asList:['Name', 'Test']
第一个结果对我来说是有意义的,第二个结果是不直观的。我期望一个嵌套的结果-一个带有list的dict的dict。
- 是什么导致了这种不直观的行为?如何缓解?**
2条答案
按热度按时间1wnzp6jl1#
目前,我使用的是一种简单的变通方法,请参见https://trinket.io/python3/7ccaa91f7e
输出:
zbdgwd5y2#
语法问题是:您将OneOrMore封装在delimited_list中,并且只需要外部的一个,并且没有告诉解析器需要如何构造数据以给予名称意义。
您也不需要空白抑制,因为它是自动的。
将parse_all添加到parse_string函数将有助于查看哪些地方没有消耗所有内容。
list_all_matches
请求返回所有匹配项只对一些简单结构有用,但它确实有效。请参阅下面的示例。pyparsing.Group
来告诉解析器不要将其内容扁平化到父列表中(从而保留有用的结构和部分名称)。Group
以进行救援。第一个有意义,它给了你一个你所期望的所有标记的列表;第三个也有意义,因为你有一个你可以走的结构;但是第二个你最终得到了两个列表,这两个列表(在一个更复杂的语法中)不一定很容易匹配。
这里有一种构建语法的不同方法,它支持用引号括起带有分隔符的字符串,这样它们就不会变成列表,也不会变成不在Map中的关键字。如果没有解析操作,要做到这一点就比较困难了。