Skip to main content
 首页 » 编程设计

python之pyparsing 中的 asDict 方法覆盖先前的键

2024年09月03日34yyy_WW

我有一个我面临的问题的人为示例:

import pyparsing as pp 
 
fname = pp.OneOrMore( pp.Word("Max") ).setResultsName("fname") 
mname = pp.OneOrMore(s pp.Word("Joseph") ).setResultsName("mname") 
lname = pp.OneOrMore( pp.Word("Andrews") ).setResultsName("lname") 
another_mname = pp.OneOrMore(pp.Word("Miller")).setResultsName("mname") 
 
full = fname + mname + lname + another_mname 
 
output = full.parseString("Max Joseph Joseph Andrews Miller Miller").asDict() 
 
# current output  
{'fname': ['Max'], 'lname': ['Andrews'], 'mname': ['Miller', 'Miller']} 

很明显为什么输出是这样的。但是,我还想收集“约瑟夫”作为另一个值(value)。例如

# desired output 
{'fname': ['Max'], 'lname': ['Andrews'], 'mname': ['Joseph', 'Joseph', 'Miller', 'Miller']} 

谢谢。

请您参考如下方法:

您的代码不起作用,因为您将结果的名称设置为相同。 这会导致 "mname" 条目与 mname 在生成的 dict() 中被替换为 "mname" 条目关联到 another_mname。

解决此问题的一种方法是将名称收集到两个单独的结果中,然后加入它们:

import pyparsing as pp 
 
fname = pp.OneOrMore(pp.Word("Max"))("fname") 
mname = pp.OneOrMore(pp.Word("Joseph"))("mname") 
lname = pp.OneOrMore(pp.Word("Andrews"))("lname") 
another_mname = pp.OneOrMore(pp.Word("Miller"))("mname2") 
 
full = fname + mname + lname + another_mname 
 
output = full.parseString("Max Joseph Joseph Andrews Miller Miller").asDict() 
print(output) 
# {'fname': ['Max'], 'mname': ['Joseph', 'Joseph'], 'lname': ['Andrews'], 'mname2': ['Miller', 'Miller']} 
 
# clean-up dict 
output['mname'] = output['mname'] + output['mname2'] 
del output['mname2'] 
 
print(output) 
# {'fname': ['Max'], 'mname': ['Joseph', 'Joseph', 'Miller', 'Miller'], 'lname': ['Andrews']} 

请注意,您不能简单地将 mname 定义为:

mname = pp.OneOrMore(pp.Word("Joseph") | pp.Word("Miller"))("mname") 

这会导致类似的问题:

import pyparsing as pp 
 
fname = pp.OneOrMore(pp.Word("Max"))("fname") 
mname = pp.OneOrMore(pp.Word("Joseph") | pp.Word("Miller"))("mname") 
lname = pp.OneOrMore(pp.Word("Andrews"))("lname") 
 
full = fname + mname + lname + mname 
 
output = full.parseString("Max Joseph Joseph Andrews Miller Miller").asDict() 
print(output) 
# {'fname': ['Max'], 'mname': ['Miller', 'Miller'], 'lname': ['Andrews']} 

但出于不同的原因:现在 full 末尾的 mname 正在替换 mname 的先前值。


也可以将其自动化,例如

import pyparsing as pp 
 
fname = pp.OneOrMore(pp.Word("Max"))("fname") 
mname = pp.OneOrMore(pp.Word("Joseph"))("mname:0") 
lname = pp.OneOrMore(pp.Word("Andrews"))("lname") 
another_mname = pp.OneOrMore(pp.Word("Miller"))("mname:1") 
 
full = fname + mname + lname + another_mname 
 
output = full.parseString("Max Max Joseph Joseph Andrews Miller Miller").asDict() 
print(output) 
# {'fname': ['Max', 'Max'], 'mname:0': ['Joseph', 'Joseph'], 'lname': ['Andrews'], 'mname:1': ['Miller', 'Miller']} 
 
 
def quench(pp_dict, mapping=lambda k: k.split(':')[0]): 
    result = {} 
    to_remove = [] 
    for k, v in pp_dict.items(): 
        new_k = mapping(k) 
        if k != new_k: 
            if new_k not in result: 
                result[new_k] = [] 
            result[new_k].extend(v) 
        else: 
            result[k] = v 
    return result 
 
 
print(quench(output)) 
# {'fname': ['Max', 'Max'], 'mname': ['Joseph', 'Joseph', 'Miller', 'Miller'], 'lname': ['Andrews']} 

或者,通过自动将多个 "mname" 实例转换为 编号 实例(例如 "mname :0") 稍后被淬火。


编辑

(正如@PaulMcG 所指出的)

这种机制直接在pyparsing中实现:

import pyparsing as pp 
 
fname = pp.OneOrMore(pp.Word("Max")).setResultsName("fname") 
mname = pp.OneOrMore(pp.Word("Joseph")).setResultsName("mname", listAllMatches=True) 
lname = pp.OneOrMore(pp.Word("Andrews")).setResultsName("lname") 
another_mname = pp.OneOrMore(pp.Word("Miller")).setResultsName("mname", listAllMatches=True) 
 
full = fname + mname + lname + another_mname 
 
output = full.parseString("Max Joseph Joseph Andrews Miller Miller").asDict() 
print(output) 
# {'fname': ['Max'], 'mname': [['Joseph', 'Joseph'], ['Miller', 'Miller']], 'lname': ['Andrews']} 

甚至像这样:

import pyparsing as pp 
 
fname = pp.OneOrMore(pp.Word("Max")).setResultsName("fname") 
mname = pp.OneOrMore(pp.Word("Joseph") | pp.Word("Miller")).setResultsName("mname", listAllMatches=True) 
lname = pp.OneOrMore(pp.Word("Andrews")).setResultsName("lname") 
 
full = fname + mname + lname + mname 
 
output = full.parseString("Max Joseph Joseph Andrews Miller Miller").asDict() 
print(output) 
# {'fname': ['Max'], 'mname': [['Joseph', 'Joseph'], ['Miller', 'Miller']], 'lname': ['Andrews']} 

尽管结果是 list 的 list 而不是单个扁平化的。