3
votes

générer dynamiquement des regex à partir des clés du dictionnaire python

dic = { 'k1':'v1', 'k2':'v2' }

4 commentaires

t_FUNC_ renvoie son deuxième paramètre. Il ne renvoie pas de regex.


@DYZ: C'est ainsi que fonctionne PLY. L'expression régulière est tirée de la docstring de la fonction et la fonction est appelée uniquement après que l'expression régulière est mise en correspondance (et uniquement si l'expression régulière correspond). Le deuxième paramètre de la fonction d'action - en fait le premier argument puisque OP utilise une classe lexer - est l'objet de jeton que le scanner a déjà construit; l'idée est que la fonction d'action peut modifier l'objet de jeton comme elle le souhaite avant qu'il ne soit transmis à l'analyseur. Il peut même fabriquer un objet jeton entièrement nouveau, en renvoyant autre chose que l'argument qui lui est donné.


@rici C'est ce que j'ai pensé. Mais toujours la fonction ne retourne pas l'expression régulière, contrairement à ce que prétend l'OP.


@dyz: vrai, mais je soupçonne fortement que ce n'était qu'une simple erreur de formulation. Je doute que l'anglais soit la langue maternelle d'OP. Voir leur question précédente stackoverflow.com/questions/54048095/... pour une description un peu plus claire, qui doit encore être lue avec un peu de générosité.


3 Réponses :


2
votes

Mettre les clés du dict dans votre regex est aussi simple que:

Code:

(?i)k1|(?i)k2

Code de test:

data = {'k1': 'v1', 'k2': 'v2'}
regex = '|'.join('(?i){}'.format(k) for k in data)
print(regex)


7 commentaires

À peu près sûr que vous n'avez besoin du (? I) qu'une seule fois, au début du modèle.


@CertainPerformance, je ne sais rien du modèle, traduisait simplement la chaîne demandée par OP.


(? i) démarre le mode insensible à la casse.


Cela ne fonctionnera pas avec Ply. Du moins, pas sans écrire un lexer personnalisé entier.


@rici, cool. Pourquoi pas?


@rici pouvez-vous s'il vous plaît écrire un exemple


PLY souhaite générer un lexer statique en analysant les commentaires doc des fonctions qui correspondent à un schéma de nommage. Vous essayez de générer dynamiquement l'expression régulière lorsque la fonction est appelée, ce qui est bien trop tard pour travailler avec PLY. Voir la documentation 't_id' de PLY pour une solution possible.



0
votes
'(?i)'+'|'.join(re.escape(k) for k in dic)
You need the re.escape in case one of the dic keys happen to contain a control character in the regex language (like |). Also, the use of global inline flags like (?i) is deprecated anywhere in the pattern but the start. (If you only want it to apply to part of the expression, you can use the new local flag syntax, (?i:foo).)

1 commentaires

La question initiale concerne la génération de lexers avec [ply]. Puisque Ply ne permet pas la modification dynamique des expressions régulières après la génération du scanner lexical, cette réponse n'est pas particulièrement pertinente pour la question réelle.



1
votes

Comme @AustinHastings le dit dans un commentaire, Ply construit le scanner lexical en combinant les expressions régulières fournies dans le lexer, soit en tant que valeurs des membres de classe, soit en tant que docstrings des fonctions membres de classe. Une fois le scanner construit, il ne sera pas modifié, donc vous ne pouvez vraiment pas ajuster dynamiquement les expressions régulières, du moins pas après que le scanner a été généré.

Pour l'application particulière que vous avez à l'esprit, cependant, ce n'est pas nécessaire pour créer une expression régulière personnalisée. Vous pouvez utiliser la procédure beaucoup plus simple illustrée dans le le manuel Ply qui montre comment reconnaître les mots réservés sans expression régulière personnalisée pour chaque mot.

L'idée est vraiment simple. Les mots réservés - les noms de fonction dans votre cas - sont généralement des exemples spécifiques d'un modèle plus général déjà utilisé dans le scanner lexical. C'est presque certainement le cas, car le scanner lexical doit reconnaître chaque jeton d'une manière ou d'une autre, donc avant qu'un mot généré dynamiquement ne soit ajouté au scanner, il doit avoir été reconnu comme autre chose. Plutôt que d'essayer de remplacer cet autre modèle pour l'instance spécifique, nous laissons simplement reconnaître le jeton, puis corrigeons son type (et éventuellement sa valeur) avant de renvoyer le jeton.

Voici une version légèrement modifiée du jeton exemple du manuel Ply:

cost = 3

(Vous voudrez peut-être ajuster ce qui précède pour qu'il fasse quelque chose avec la valeur associée à la clé dans le funcs code > dictionnaire, bien que cela puisse tout aussi bien être fait plus tard lors de l'analyse sémantique.)

Puisque le dictionnaire funcs ne participe en aucun cas à la génération du lexer (ou de l'analyseur ), aucune habileté particulière n'est nécessaire pour le transmettre à l'objet Lexer. En effet, il n'a même pas besoin d'être dans l'objet lexer; vous pouvez ajouter l'objet parser à l'objet lexer lorsque l'objet lexer est construit, vous permettant de placer le dictionnaire dans l'objet parser, où il est plus accessible aux actions de l'analyseur.

L'une des raisons pour lesquelles cela est une bien meilleure solution que d'essayer de construire une expression régulière personnalisée, c'est qu'elle ne reconnaît pas les mots réservés qui se trouvent être trouvés comme préfixes de mots non réservés. Par exemple, si cos était l'une des fonctions et que vous aviez réussi à produire l'équivalent de

t_ID = r'[a-zA-Z_][a-zA-Z_0-9]*'
def t_FUNC(t):
    r'(?i)sin|cos|tan'
    # do something

alors vous trouveriez que: p>

def t_ID(t):
     r'[a-zA-Z_][a-zA-Z_0-9]*'
     # Apparently case insensitive recognition is desired, so we use
     # the lower-case version of the token as a lookup key. This means
     # that all the keys in the dictionary must be in lower-case
     token = t.value.lower()
     if token in self.funcs:
         t.type = 'FUNC'
     return t

a été scanné comme FUNC (cos), ID (t), '=', NUMBER (3) , ce qui n'est certainement pas ce que vous voulez . Mettre la logique à l'intérieur de la fonction t_ID évite complètement ce problème, puisque seuls les jetons complets seront considérés.


0 commentaires