各行がゲーム ユニットを説明する、比較的単純なテキストを解析しています。解析手法についての知識がほとんどないため、次のアドホック ソリューションを使用しました。
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」に設定されますが、後の機能は ('Motorized', 'Armored') に変更されました。
このコードを変換して、EBNF または pyparsing 文法などを使用することを考えています。私の目標は次のとおりです。
- このコードをより簡潔にし、エラーを起こしにくくする
- 値のリストを使用したケースの醜い扱いを回避します(最初に正規表現内で置換を行い、後で結果を後処理して文字列をリストに変換する必要があります)
何を使用し、コードをどのように書き直すかについて、あなたの提案は何ですか?
PS 混乱を避けるために、コードの一部をスキップしました。プロセスにエラーが発生した場合は、申し訳ありません-元のコードは機能します:)