Я основал свой ответ на этом , поскольку вы пытаетесь получить не жадное совпадение. Кажется, что это трудно сделать при разборе, но не невозможно при некоторой сообразительности и компромиссе. Кажется, работает следующее:
from pyparsing import *
Parameter = Literal('SPEED_X') | Literal('SPEED_Y') | Literal('SPEED_Z')
UndParam = Suppress('_') + Parameter
Identifier = SkipTo(UndParam)
Value = Word(nums)
Entry = Identifier + UndParam + Value
Когда мы запускаем это из интерактивного переводчика, мы видим следующее:
>>> Entry.parseString('ABC_123_SPEED_X 123')
(['ABC_123', 'SPEED_X', '123'], {})
Обратите внимание, что это компромисс; поскольку я использую SkipTo
, Identifier
может быть полон злых, отвратительных персонажей, а не просто красивых alphanums
со случайным подчеркиванием.
РЕДАКТИРОВАТЬ: Благодаря Полу Макгуайру мы можем придумать действительно элегантное решение, установив для Identifier
следующее:
Identifier = Combine(Word(alphanums) +
ZeroOrMore('_' + ~Parameter + Word(alphanums)))
Давайте посмотрим, как это работает. Во-первых, игнорируйте внешнее Combine
; мы вернемся к этому позже. Начиная с Word(alphanums)
мы знаем, что получим 'ABC'
часть строки ссылки, 'ABC_123_SPEED_X 123'
. Важно отметить, что в этом случае мы не позволяли «слову» содержать подчеркивания. Мы строим это отдельно в логике.
Далее нам нужно захватить часть '_123'
, не всасывая при этом '_SPEED_X'
. Давайте также пропустим ZeroOrMore
и вернемся к нему позже. Мы начинаем с подчеркивания как Literal
, но мы можем использовать ярлык просто с '_'
, что даст нам лидирующее подчеркивание, но не все '_123'
. По сути, мы бы поместили еще Word(alphanums)
, чтобы захватить остальные, но это именно то, что доставит нам неприятности, потребляя все оставшиеся '_123_SPEED_X'
. Вместо этого мы говорим: «Пока то, что следует за подчеркиванием , а не * Parameter
, анализируют это как часть моего Identifier
. Мы говорим, что в терминах переноса слов как '_' + ~Parameter + Word(alphanums)
. Поскольку мы предполагаем, что у нас может быть произвольное количество повторений подчеркивания + WordButNotParameter, мы оборачиваем это выражение в конструкцию ZeroOrMore
. (Если вы всегда ожидаете хотя бы подчеркивания + WordButNotParameter после начального, вы можете использовать OneOrMore
.)
Наконец, нам нужно обернуть начальное Слово и специальное подчеркивание + повторения слов вместе, чтобы понять, что они являются смежными, не разделенными пробелами, поэтому мы заключаем все выражение в конструкцию Combine
. Таким образом, 'ABC _123_SPEED_X'
вызовет ошибку разбора, но 'ABC_123_SPEED_X'
будет проанализирован правильно.
Обратите внимание, что мне пришлось изменить Keyword
на Literal
, потому что пути первого слишком тонки и быстры, чтобы злиться. Я не доверяю Keyword
с, и я не могу получить соответствие с ними.