Pyparsing: группировка результатов по ключевым словам, заканчивающимся двоеточиями

#pyparsing

#пипаринг

Вопрос:

Я новичок в pyparsing этом деле . Хотя я и пытался прочитать документы, мне не удалось решить первую проблему группировки выражений по «ключевому слову: токен(ы)». В итоге я получил этот код:

 import pyparsing from pprint import pprint  token = pp.Word(pp.alphas) keyword = pp.Combine(token   pp.Literal(":")) expr = pp.Group(keyword[1]   token[1, ...])  pprint(expr.parse_string("keyA: aaa bb ccc keyB: ddd eee keyC: xxx yyy hhh zzz").as_list())  

Он останавливается посередине и анализирует второй keyword как обычный токен. В результате получается следующее:

выражение:

 keyA: aaa bb ccc keyB: ddd eee keyC: xxx yyy hhh zzz  

разбирается на:

 [['keyA:', 'aaa', 'bb', 'ccc', 'keyB']]  

Я не могу понять, как определить keyword и token .


Редактировать.

В общем, я хотел бы разобрать следующее выражение:

 keyword1: token11 token12 ... keyword2: token21 amp; token22 token23 keyword3: (token31 token32) amp; token33  

в следующий список:

 [  ["keyword1:", "token11", "token12", ...],  ["keyword2:", ["token21", "amp;", "token22"], "token23"],  ["keyword3:", [["token31", "token32"], "amp;", "token33"]], ]  

Ответ №1:

Хорошо, поэтому я искал способ указать, что token заканчивается буквенно-цифровым символом, то есть нет : . Оказывается, у Pyparsing есть функция WordEnd() , которую я использовал, с помощью которой выражение правильно анализируется.

 import pyparsing from pprint import pprint  token = pp.Combine(pp.Word(pp.alphas)   pp.WordEnd()) keyword = pp.Combine(pp.Word(pp.alphas)   pp.Literal(":")) expr = pp.Group(keyword[1]   token[1, ...])[1, ...]  pprint(expr.parse_string("keyA: aaa bb ccc keyB: ddd eee keyC: xxx yyy hhh zzz").as_list())  
 [['keyA:', 'aaa', 'bb', 'ccc'],  ['keyB:', 'ddd', 'eee'],  ['keyC:', 'xxx', 'yyy', 'hhh', 'zzz']]  

Комментарии:

1. Рад видеть, что вы решили эту проблему. Вместо WordEnd() этого вы также можете попробовать отрицательный внешний вид , используя оператор ‘~’ ( NotAny ) и FollowedBy , как в token = Word(alphas) ~FollowedBy(":") .

Ответ №2:

Чтобы добавить поддержку оператора»amp;», как в вашем первоначальном посте, вы были очень близки к использованию infixNotation . В вашем оригинале у вас было выражение типа «a b amp; c», которое вы хотели разобрать как ['a', ['b', 'amp;', 'c'] . Первая проблема, с которой вы столкнулись, была связана с проблемой «токен против ключа», которую вы решили для себя. Вторая проблема связана с вашими операторами. Можно infixNotation определить пустой оператор, используя Python None для выражения оператора. Поскольку вы определили свое выражение так, чтобы оно имело более низкий приоритет, чем»amp;», то вы бы определили свое выражение как:

 expr = infixNotation(token,  [  ('amp;', 2, opAssoc.LEFT,),  (None, 2, opAssoc.LEFT,),  ])  

Используйте рантесты для быстрого выполнения множества тестов:

 expr.runTests("""  a b c  a amp; b  a amp; b amp; c  a amp; b c  a amp; (b c) """, fullDump=False)  

С принтами:

 a b c [['a', 'b', 'c']]  a amp; b [['a', 'amp;', 'b']]  a amp; b amp; c [['a', 'amp;', 'b', 'amp;', 'c']]  a amp; b c [[['a', 'amp;', 'b'], 'c']]  a amp; (b c) [['a', 'amp;', ['b', 'c']]]  

Комментарии:

1. Спасибо. Мой анализ был значительно расширен с тех пор, как я задал этот вопрос. Я принял во внимание ваш совет и добавил новые строки в код. До сих пор, похоже, он все разбирает правильно. Единственное, чего не хватает, — это как добавить nested_expr() . Я не могу этого понять. Я совсем новичок в pyparsing 🙂

2. Вам не нужно добавлять nested_expr() скобки для обработки (см. Последний тестовый пример выше). infix_notation включает поддержку группировки с помощью ().