Я разбираю относительно простой текст, где каждая строка описывает игровое устройство. У меня мало знаний разбора техники, поэтому я использовал следующий специальный раствор:python: замена регулярного выражения на BNF или pyparsing
class Unit:
# rules is an ordered dictionary of tagged regex that is intended to be applied in the given order
# the group named V would correspond to the value (if any) for that particular tag
rules = (
('Level', r'Lv. (?P<V>\d+)'),
('DPS', r'DPS: (?P<V>\d+)'),
('Type', r'(?P<V>Tank|Infantry|Artillery'),
#the XXX will be expanded into a list of valid traits
#note: (XXX|)* wouldn't work; it will match the first space it finds,
#and stop at that if it's in front of something other than a trait
('Traits', r'(?P<V>(XXX)(XXX|)*)'),
# flavor text, if any, ends with a dot
('FlavorText', r'(?P<V>.*\."?$)'),
)
rules = collections.OrderedDict(rules)
traits = '|'.join('All-Terrain', 'Armored', 'Anti-Aircraft', 'Motorized')
rules['Traits'] = re.sub('XXX', effects, rules['Traits'])
for x in rules:
rules[x] = re.sub('<V>', '<'+x+'>', rules[x])
rules[x] = re.compile(rules[x])
def __init__(self, data)
# data looks like this:
# Lv. 5 Tank DPS: 55 Motorized Armored
for field, regex in Item.rules.items():
data = regex.sub(self.parse, data, 1)
if data:
raise ParserError('Could not parse part of the input: ' + data)
def parse(self, m):
if len(m.groupdict()) != 1:
Exception('Expected a single named group')
field, value = m.groupdict().popitem()
setattr(self, field, value)
return ''
Это прекрасно работает, но я чувствую, что достиг предела регулярных выражений власти. В частности, в случае с чертами значение становится строкой, которую мне нужно разделить и преобразовать в список в более поздней точке: например, obj.Traits будет установлен в «Motorized Armored» в этом коде, но в позже функция изменилась на («Моторизованный», «Бронированный»).
Я собираюсь преобразовать этот код, чтобы использовать грамматику EBNF или pyparsing или что-то в этом роде. Мои цели:
- делает этот код аккуратнее и менее подвержены ошибкам
- избежать уродливых лечений случае со списком значений (где мне нужно сделать замену внутри регулярного выражения первой, а позже пост-процессом результат, чтобы преобразовать строку в список)
Каковы были бы ваши предложения по поводу того, что использовать и как переписать код?
P.S. Я пропустил некоторые части кода, чтобы избежать беспорядка; если я представил какие-либо ошибки в этом процессе, извините - исходный код действительно работает :)
Я предлагаю для pyparsing. Легко писать чистый код. Посмотрите примеры @ http://pyparsing.wikispaces.com/Examples. – asb
Должен ли я использовать EBNF, а затем скомпилировать его с помощью http://pyparsing.wikispaces.com/file/view/ebnf.py, чтобы создать грамматику pyparsing? Или я должен писать pyparsing грамматику напрямую? – max