Pyparsing - Проблемы с разбором файла в структуру словаря

Я пытаюсь использовать Pyparsing для анализа файлов формата Aspartix(.apx) (http://www.dbai.tuwien.ac.at/research/project/argumentation/systempage/docu.htm), и у меня возникли проблемы со структурированием результатов в словаре.

Я определил грамматику следующим образом:

from pyparsing import *

ID = Word(alphanums)
arg_pair = Group(ID + Suppress(',') + ID)
value = Word(nums)
lineEnd = Suppress(').')
arg = Suppress('arg(') + ID + lineEnd
attack = Suppress('att(') + arg_pair + lineEnd
pref = Suppress('pref(') + arg_pair + lineEnd
val = Suppress('val(') + ID + Suppress(',') + value + lineEnd
valpref = Suppress('valpref(') + value + Suppress(',') + value +  lineEnd
support = Suppress('support(') + arg_pair + lineEnd

apx = OneOrMore(arg.setName('arg') | attack.setName('att') | pref.setName('pref') | val.setName('val') | valpref.setName('valpref') | support.setName('support'))

Я не уверен, как использовать функцию setName() для определения ключей словаря, чтобы каждое вхождение правил arg, атаки и т. д. сопоставлялось с определенным ключом. Использование приведенного выше кода не дает пригодных для использования ключей словаря.

Например:

"""arg(a).
arg(b).
att(a,b)."""

Сопоставил бы с:

{"arg": ["a","b"], "att":[["a","b"]]}

Буду признателен за любую помощь, которую вы можете оказать.


person robobbo    schedule 09.06.2015    source источник
comment
вообще непонятно что вы пытаетесь конвертировать и в какой формат   -  person    schedule 09.06.2015
comment
Я пытаюсь разобрать вхождения arg, Attack, Pref и т. д. в dict. Например, аргумент(а). \n аргумент(б). \n att(a,b) будет отображаться в {arg : [a, b], att: [[a,b]]}   -  person robobbo    schedule 09.06.2015
comment
Вы путаете setName() (которое называет выражение, полезное для переопределения сгенерированного по умолчанию имени выражения, используемого в исключениях синтаксического анализа) с setResultsName() (которое называет результаты, определяя ключи, подобные dict в результатах анализа). После того, как вы исправите это, вы можете еще больше навести порядок, используя вызываемую форму — замените expr.setResultsName("xyzzy") на expr("xyzzy").   -  person PaulMcG    schedule 09.06.2015
comment
Вау, как глупо с моей стороны. Я внес исправления, однако, когда я пытаюсь получить доступ к словарю по ключу (например, result['arg']), я получаю только окончательное значение arg из входного потока.   -  person robobbo    schedule 09.06.2015
comment
Обратите внимание в моем ответе, что, когда группы удалены и все ключи находятся на одном уровне в результатах, я меняю имя с arg на arg*, что эквивалентно .setResultsName("arg",listAllMatches=True).   -  person PaulMcG    schedule 10.06.2015
comment
Спасибо за объяснение, Павел. Мне было интересно, что делает этот модификатор.   -  person robobbo    schedule 10.06.2015
comment
По какой-то причине люди никогда не узнают об онлайн-документах. Вот примечания к setResultsName и аналогичному синтаксису __call__(): pythonhosted.org/ pyparsing/ и pythonhosted.org/pyparsing/   -  person PaulMcG    schedule 10.06.2015


Ответы (1)


Несколько других комментариев к вашему парсеру:

  • Как правило, вам следует избегать определения литералов, которые объединяют ключевые слова с соответствующей пунктуацией. Например, определение arg как Suppress('arg(') будет искать специально для "arg()", если между ключевым словом и открывающей скобкой есть пробелы. Вместо этого я рекомендую определять ваши ключевые слова с помощью класса Keyword. Вы можете подавить их, если хотите, но ключевое слово обеспечит полное совпадение слова и защитит от случайного совпадения ведущего «val» из «valpref».

  • Определение ID как Word(alphanums) откроет дверь для путаницы между ID и целочисленными значениями. Я ожидаю, что идентификаторы всегда будут начинаться как минимум с буквенного символа, поэтому вы можете использовать форму Word с двумя аргументами, чтобы указать альфа только как набор разрешенных начальных символов, а буквенные числа как набор разрешенных символов тела.

  • См. мой комментарий к вашему сообщению: setName() vs setResultsName()

Я немного перенастроил ваш парсер, чтобы все команды имели одинаковые клавиши: "cmd" и "args". Это позволяет писать полиморфный код, например цикл for в конце этого примера.

from pyparsing import *
LPAR,RPAR,DOT,COMMA = map(Suppress,"().,")
arg,attack,pref,val,valpref,support = map(Keyword, 
    "arg att pref val valpref support".split())

ID = Word(alphas, alphanums)
id_pair = Group(ID + COMMA + ID)
integer = Word(nums)
int_pair = Group(integer + COMMA + integer)

arg_cmd = Group(arg("cmd") + LPAR + ID("args") + RPAR)
attack_cmd = Group(attack("cmd") + LPAR + id_pair("args") + RPAR)
pref_cmd = Group(pref("cmd") + LPAR + id_pair("args") + RPAR)
val_cmd = Group(val("cmd") + LPAR + Group(ID + COMMA + integer)("args") + RPAR)
valpref_cmd = Group(valpref("cmd") + LPAR + int_pair("args") + RPAR)
support_cmd = Group(support("cmd") + LPAR + id_pair("args") + RPAR)

apx = OneOrMore((arg_cmd | attack_cmd | pref_cmd | val_cmd | valpref_cmd | support_cmd) + DOT)

for command in apx.parseString(apxSource):
    print command.dump()
    print command.cmd
    print command.args

Если вы хотите следовать своему первоначальному плану именования, я думаю, это будет выглядеть примерно так.

arg_cmd = Group(arg + LPAR + ID("arg") + RPAR)
attack_cmd = Group(attack + LPAR + id_pair("attack") + RPAR)
pref_cmd = Group(pref + LPAR + id_pair("pref") + RPAR)
val_cmd = Group(val + LPAR + Group(ID + COMMA + integer)("val") + RPAR)
valpref_cmd = Group(valpref + LPAR + int_pair("valpref") + RPAR)
support_cmd = Group(support + LPAR + id_pair("support") + RPAR)

Или это.

arg_cmd = (arg + LPAR + ID("arg*") + RPAR)
attack_cmd = (attack + LPAR + id_pair("attack*") + RPAR)
pref_cmd = (pref + LPAR + id_pair("pref*") + RPAR)
val_cmd = (val + LPAR + Group(ID + COMMA + integer)("val*") + RPAR)
valpref_cmd = (valpref + LPAR + int_pair("valpref*") + RPAR)
support_cmd = (support + LPAR + id_pair("support*") + RPAR)

Как видите, существует множество подходов к созданию этих синтаксических анализаторов и результирующих анализируемых структур, вращающихся вокруг личного стиля, а также правильного и неправильного. В последних двух примерах не определены имена «cmd» или «args», поэтому вам придется удалить их из приведенного выше примера кода цикла for. Если вы ищете dict-key, например синтаксический анализ, я думаю, что последняя структура будет больше всего похожа на то, что вы ищете. Однако обратите внимание, что этот синтаксический анализатор отбрасывает порядок, в котором находятся команды. Если порядок важен, вам, вероятно, следует использовать один из первых двух примеров, поскольку классы Group сохранят порядок команд без изменений.

person PaulMcG    schedule 09.06.2015