Я анализирую относительно простой текст, где каждая строка описывает игровой блок. У меня мало знаний о методах разбора, поэтому я использовал следующее специальное решение:
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 ''
Работает нормально, но я чувствую, что достиг предела мощности регулярных выражений. В частности, в случае с Traits значение в итоге становится строкой, которую мне нужно разделить и преобразовать в список на более позднем этапе: например, в этом коде obj.Traits будет установлен на «Motorized Armored», но в более поздняя функция изменилась на («Моторизованный», «Бронированный»).
Я думаю о том, чтобы преобразовать этот код для использования либо EBNF, либо грамматики переноса, либо чего-то в этом роде. Мои цели:
- делает этот код более аккуратным и менее подверженным ошибкам
- избегать безобразного обращения к регистру со списком значений (где мне нужно сначала выполнить замену внутри регулярного выражения, а затем обработать результат для преобразования строки в список)
Что бы вы посоветовали о том, что использовать и как переписать код?
P.S. Я пропустил некоторые части кода, чтобы избежать беспорядка; если я внес какие-либо ошибки в процесс, извините - оригинальный код работает:)