12
votes

Python - Analyse lexicale et tokénisation

Je cherche à accélérer le long de mon processus de découverte ici un peu, car c'est ma première entreprise dans le monde de l'analyse lexicale. Peut-être que c'est même le mauvais chemin. Tout d'abord, je vais décrire mon problème:

J'ai des fichiers de propriétés très volumineux (de l'ordre de 1 000 propriétés), qui, lorsqu'ils sont distillés, sont vraiment d'environ 15 propriétés importantes et que le reste peut être généré ou rarement jamais changé. . p>

Donc, par exemple: p> xxx pré>

Ceci est le type de format que je veux créer pour jetonner quelque chose comme: p> xxx PRE>

dans P>

property.mynameblah.home.directory = /blah
property.myname.ip = 127.0.0.1
property.component1.ip = 127.0.0.1
property.component1.foo = bar


3 commentaires

Pourquoi ne pas utiliser Json au lieu de créer votre propre analyseur ??


Votre exemple de traduction semble avoir des erreurs dedans. Sinon, je ne vois pas pourquoi "$ {composent1} .ip" a été traduit en "composant1" dans la ligne 3 de l'exemple. Si la syntaxe est celle-ci, j'entraînerais probablement les identificateurs $ {identifiants} avec des expressions régulières et les remplacer avec les recherches de dictionnaire de la réussite sans entrée de dictionnaire.


Il y avait quelques erreurs là-bas, je pense que je leur ai corrigé.


5 Réponses :


1
votes

Si vous pouvez modifier le format des fichiers d'entrée, vous pouvez utiliser un analyseur pour un format existant, tel que JSON.

Cependant, de votre déclaration de problème, cela ressemble à ce qui n'est pas le cas. Donc, si vous souhaitez créer un lexer and parseur personnalisé, utilisez pli (Python Lex / Yacc). Il est facile à utiliser et fonctionne de la même manière que Lex / Yacc.

Voici un lien vers un exemple d'une calculatrice construite à l'aide de Ply. Notez que tout commence par t _ est une règle LXER - définissant un jeton valide - et tout commençant par p _ est une règle d'analyse qui définit une production de la grammaire.


0 commentaires

2
votes

Pour aussi simple que votre format semble être, je pense qu'un parseur complet / lexer serait une voie trop excédentaire. On dirait qu'une combinaison de regexes et de manipulation de chaîne ferait l'affaire.

Une autre idée est de changer le fichier à quelque chose comme JSON ou XML et utiliser un package existant.


0 commentaires

4
votes

Un simple DFA fonctionne bien pour cela. Vous n'avez besoin que de quelques états:

  1. à la recherche de $ {
  2. vu $ { à la recherche d'au moins un caractère valide formant le nom
  3. Vu au moins un caractère de nom valide, recherchant plus de caractères de nom ou } .

    Si le fichier de propriétés est commandé agnostique, vous pouvez souhaiter qu'un processeur de deux passeurs vérifie que chaque nom résout correctement.

    Bien sûr, vous devez ensuite écrire le code de substitution, mais une fois que vous avez une liste de tous les noms utilisés, la mise en œuvre la plus simple possible est une recherche / remplacement sur $ {nom} avec son valeur correspondante.


1 commentaires

+ Up DFA / NFA est toujours le meilleur.



1
votes

La syntaxe que vous fournissez semble similaire à Mako Modèles Moteur . Je pense que vous pourriez essayer, c'est une API plutôt simple.


0 commentaires

13
votes

Il y a un excellent article sur Utilisation d'expressions régulières pour l'analyse lexicale à effabot.org .

Adaptation du Tokenizer à votre problème: P>

========================== stuff ===========================
('identifier', 'property')
('dot', '.')
('open_variable', '${')
('identifier', 'general')
('dot', '.')
('identifier', 'name')
('close_curly', '}')
('dot', '.')
('identifier', 'ip')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('open_variable', '${')
('identifier', 'general')
('dot', '.')
('identifier', 'ip')
('close_curly', '}')
========================== stuff2 ==========================
('newline', '\n')
('identifier', 'general')
('whitespace', ' ')
('open_curly', '{')
('newline', '\n')
('whitespace', '  ')
('identifier', 'name')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('identifier', 'myname')
('newline', '\n')
('whitespace', '  ')
('identifier', 'ip')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('integer', '127')
('dot', '.')
('integer', '0')
('dot', '.')
('integer', '0')
('dot', '.')
('integer', '1')
('newline', '\n')
('close_curly', '}')
('newline', '\n')


1 commentaires

Fyi, Ce type de tokéniseur a fait entrer dans la Documentation STDLIB du module re