#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
включает поддержку группировки с помощью ().