pyparsing: разделить цепочку вызовов методов на части верхнего уровня - PullRequest
1 голос
/ 30 апреля 2019

Если у меня есть цепочка вызовов методов в Python, как мне извлечь вызовы верхнего уровня с помощью pyparsing?

Tldr;функция должна вести себя так:

_parse_commands("df.hi()[['fi']](__call__).NI(ni='NI!')")
['df', '.hi()', "[['fi']]", '(__call__)', ".NI(ni='NI!')"]

Я даже не смог правильно проанализировать вызов метода:

from pyparsing import Word, alphas, nums, Literal, alphanums, printables, Optional, locatedExpr, originalTextFor, SkipTo

identifier = Word(alphas + '_', alphanums + '_').setName("identifier")
lparen = Literal("(")
rparen = Literal(")")
function_call = identifier + lparen + Optional(printables) + rparen

function_call.parseString("hi()")
# (['hi', '(', ')'], {})
# but
function_call.parseString("hi(ho)")
# ...
# ParseException: Expected ")" (at char 3), (line:1, col:4)

Проблема в том, что я не могу найти какой-либо способ сказатьpyparsing, чтобы «принести мне что-нибудь между разделителями» - это то, что я пытаюсь с печатными материалами выше.Я также пытался использовать OriginalTextFor для решения той же проблемы.

Кроме того, если в ответе можно использовать locationExpr для определения местоположения вызовов функций, это было бы здорово.

1 Ответ

1 голос
/ 30 апреля 2019

На самом деле синтаксический анализ этих выражений не будет тривиальным, так как вам нужно будет в значительной степени определить любой тип выражения Python.

Но так как вы хотите просто разбить вложенные скобки, то вы можете использовать pyparsingвстроенный nestedExpr() (по умолчанию используется выражение nested ()) и использует scanString для сканирования входной строки на предмет совпадений.Каждое совпадение возвращает кортеж токенов, начальное и конечное местоположение.Отслеживая последний увиденный конец, затем, когда есть совпадение, вы можете восстановить промежуточный текст, разрезая от last_end до текущего начала:

src = "df.hi()[['fi']](__call__).NI(ni='NI!')"
import pyparsing as pp

last_e = 0
for t, s, e in pp.nestedExpr().scanString(src):
    print(src[last_e:s])
    print(s)
    print(t.asList())
    print(src[s:e])
    print(e)
    print()
    last_e = e

# get whatever is left after the last parens
print(src[last_e:])

Отпечатки:

df.hi
5
[[]]
()
7

[['fi']]
15
[['__call__']]
(__call__)
25

.NI
28
[['ni=', "'NI!'"]]
(ni='NI!')
38

Отздесь вы сможете получить нужные биты.

...