Ваш код не работает, потому что вы задаете имя результатов, которые будут одинаковыми.Это приводит к тому, что запись "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']}
но по другой причине: теперь mname
в конце full
заменяет предыдущее значение 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']}
или, что еще более бессмысленно, путем предварительной обработки full
путем автоматического преобразования нескольких "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
с, а не один сплющенныйодин.