Не жадный разбор списка с помощью pyparsing



У меня есть строка, состоящая из списка слов, которые я пытаюсь разобрать с помощью pyparsing.



Список всегда содержит минимум три пункта. Из этого я хочу, чтобы pyparsing генерировал три группы, первая из которых содержит все слова до последних двух элементов, а последние две группы должны быть последними двумя элементами. Например:



"one two three four"


Следует разобрать на что-то похожее:



["one two"], "three", "four"


Я могу сделать это с регулярным выражением:



import pyparsing as pp
data = "one two three four"
grammar = pp.Regex(r"(?P<first>(w+W?)+)s(?P<penultimate>w+) (?P<ultimate>w+)")
print(grammar.parseString(data).dump())


Который дает:



['one two three four']
- first: one two
- penultimate: three
- ultimate: four


Моя проблема заключается в том, что я не могу получить тот же результат с Нерегексным ParserElement из-за жадной природы pyparsing, например следующее:



import pyparsing as pp
data = "one two three four"
word = pp.Word(pp.alphas)
grammar = pp.Group(pp.OneOrMore(word))("first") + word("penultimate") + word("ultimate")
grammar.parseString(data)


Сбой при трассировке:



Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/site-packages/pyparsing.py", line 1125, in parseString
raise exc
pyparsing.ParseException: Expected W:(abcd...) (at char 18), (line:1, col:19)


Потому что OneOrMore хлебает все слова в списке. Мои попытки до сих пор предотвратить это жадное поведение с помощью FollowedBy или NotAny терпят неудачу - любые предложения о том, как я могу получить желаемое поведение?

464   1  

1 ответ:

Ну, ваше выражение OneOrMore просто нужно немного подтянуть - вы на правильном пути с FollowedBy. Вы на самом деле не хотите просто OneOrMore(слово), вы хотите "OneOrMore(слово, за которым следует по крайней мере еще 2 слова)". Чтобы добавить этот вид lookahead к pyparsing, вы можете даже использовать новый оператор умножения '*' для указания количества lookahead:

grammar = pp.Group(pp.OneOrMore(word + pp.FollowedBy(word*2)))("first") + word("penultimate") + word("ultimate")

Теперь сброс этого дает желаемое:

[['one', 'two'], 'three', 'four']
- first: ['one', 'two']
- penultimate: three
- ultimate: four

Comments

    Ничего не найдено.