Je suis en train d'analyser un texte relativement simple, où chaque ligne décrit une unité de jeu. J'ai peu de connaissances des techniques de l'analyse, donc je la solution ad hoc suivante:python: remplacer regex avec BNF ou 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 ''
Il fonctionne très bien, mais je sens que j'atteint la limite du pouvoir regex. Plus précisément, dans le cas de Traits, la valeur finit par être une chaîne que je dois diviser et convertir en une liste à un point ultérieur: par exemple, obj.Traits serait mis à 'Motorized Armored' dans ce code, mais dans un la fonction ultérieure a été changée en ('Motorisé', 'Blindé').
Je pense à convertir ce code pour utiliser soit la grammaire EBNF ou pyparsing ou quelque chose comme ça. Mes objectifs sont les suivants:
- rendent cette plus propre et moins de code sujettes à erreur
- éviter le traitement laid de l'affaire avec une liste de valeurs (où je dois faire remplacer à l'intérieur du regex d'abord, et plus tard post-traitement le résultat pour convertir une chaîne en une liste)
Quelles seraient vos suggestions sur quoi utiliser, et comment réécrire le code?
P.S. J'ai sauté certaines parties du code pour éviter l'encombrement; si j'ai introduit des erreurs dans le processus, désolé - le code d'origine fonctionne :)
Je suggère pour pyparsing. Facile à écrire du code propre. Regardez les exemples @ http://pyparsing.wikispaces.com/Examples. – asb
Dois-je utiliser EBNF, puis le compiler en utilisant http://pyparsing.wikispaces.com/file/view/ebnf.py pour générer une grammaire de pyparsing? Ou devrais-je écrire la grammaire de pyparsing directement? – max