IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Expression Régulières : re.sub avec une fonction


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2011
    Messages : 2
    Par défaut Expression Régulières : re.sub avec une fonction
    Bonjour à tous,

    Je me trouve devant un petit problème lié à la fonction re.sub et aux expressions régulières.

    Je souhaiterai passer la chaîne capturer par re.sub en paramètre de la fonction eval().

    Ce qui donnerai un truc comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    maVar = '<p>test <% coucou %><p>'
    coucou = 'hello'
     
    re.sub(r'<%\s*(.+)\s%*>', eval('\\1'), maVar)

    Malheureusement j'ai une jolie erreur :
    SyntaxError: unexpected character after line continuation character
    Et je ne comprend pas bien pourquoi ça ne passerai pas.
    Y'a t'il un moyen pour que ça marche comme ça ou ce n'est pas du tout la bonne manière de procéder ?

    Merci d'avance

  2. #2
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Je crois pas que tu puisses utiliser eval ici, pas de cette façon en tout cas. Le problème est que le code \1 est géré par sub() (ou un autre élément de re), donc après l’appel à eval(), qui se retrouve donc à évaluer '\\1', ce qui ne veut pythoniquement rien dire

    Si tu passes une fonction en second argument de sub(), elle doit accepter en unique argument un objet match, donc tu dois définir une mini-fonction, voire même une lambda:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    maVar = '<p>test <% coucou %><p>'
    coucou = 'hello'
     
    re.sub(r'<%\s*(.+?)\s*%>', lambda match: eval(match.group(1)), maVar)
    (Petite correction d’une faute de frappe dans ta regex, au passage… Et j’ai aussi passé .+ en non-glouton, sinon tous tes espaces à la fin se retrouveraient dans ce que tu captures, ce qui n’est visiblement pas le but !)

    Mais c’est une manière bien risquée de procéder – si quelqu’un a accès au contenu de maVar, il peut y mettre ce qu’il veut, et le faire exécuter par eval() ! Pourquoi ne pas plutôt utiliser un dict, comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    maVar = '<p>test <% coucou %><p>'
    rep_codes = {'coucou' : 'hello'}
     
    re.sub(r'<%\s*(.+?)\s*%>', lambda match: rep_codes.get(match.group(1), ""), maVar)

  3. #3
    Candidat au Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Avril 2011
    Messages : 2
    Par défaut
    Merci pour cette réponse très claire !

    Ce pendant, j'ai essayé ta première suggestion mais il me dis que 'coucou' n'est pas déclaré (vraiment pourri comme nom de variable je sais...)
    NameError: name 'coucou' is not defined
    Je vais préciser un peu pourquoi j'ai besoin de ça, ça sera sûrement facile pour vous de m'aider.
    En fait le contenu de 'maVar' sera le contenu d'un fichier (html ou xml) et le contenu de ce fichier devra pouvoir être interprété (expression régulière + eval() me paraissaient une bonne solution) avant de passer en affichage.
    Au niveau de la sécurité, en aucun cas, l'utilisateur n'aura accès au contenu du fichier et chaque remplissage de formulaire par l'utilisateur passera par une fonction qui supprimera les occurrences '<%' et '%>' (si je décide de prendre ces balises définitivement bien sûr).

    Donc voilà l'objectif final. La deuxième solution que tu me proposais ne colle donc pas car les valeurs que contiendrai le dictionnaire ne seront pas connues lors de l'écriture du fichier source.

    Voilà, je cherche encore la meilleure façon de faire, si vous avez une idée ?

    Je suis aussi preneur de conseil sur la sécurité du système !

  4. #4
    Membre Expert

    Homme Profil pro
    Diverses et multiples
    Inscrit en
    Mai 2008
    Messages
    662
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Diverses et multiples

    Informations forums :
    Inscription : Mai 2008
    Messages : 662
    Par défaut
    Pour le “coucou” pas déclaré (t’inquiète, c’est de saison ), à mon avis, tu as oublié de le définir… En tout cas, chez moi, ce bout de code marche, en 3.2 comme en 2.6…

    De toute façon, je persiste à penser que la solution avec dictionnaire est bien plus élégante et sûre, car elle est bornée (seul le contenu du dictionnaire est accessible). Pour le contenu, tu peux parfaitement mettre à jour les valeurs d’un dictionnaire quand tu veux, voire même en ajouter ou en supprimer, par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    rep_codes = {'coucou' : "hello"}
    rep_codes['err_404'] = open("my/404/error.txt", "r").readall()
    rep_codes['usr_nick'] = get_user_nickname()
    del rep_codes['coucou']
    #etc.
    De plus, si tu as besoin de plus de souplesse et de puissance, au lieu d’utiliser eval(), assigne des fonctions à ton dict (qui peuvent même récupérer des chaînes capturées par ta regex), par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import datetime, re
     
    rep_codes = {'coucou' : lambda : "hello", # une simple chaîne statique
                 'date' : lambda : str(datetime.date.today()), # la date du jour
                }
     
    def get_user_nickname():
        # ici tu fais ta requête à la BD, par ex.
        return "einstein"
     
    rep_codes['usr_nick'] = get_user_nickname # pas de (), on assigne la fonction, pas son résultat !
     
    maVar = '<p><% coucou %> <% usr_nick %> (<% date %>)<p>'
     
    re.sub(r'<%\s*(.+?)\s*%>', lambda match: rep_codes.get(match.group(1), lambda : "")(), maVar)
    Ce qui produira :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    '<p>hello einstein (2011-04-24)<p>'


    PS : Je me doutais bien que c’était un genre de template qui était derrière tout ça

Discussions similaires

  1. expression régulière en relation avec une liste
    Par Jasmine80 dans le forum Langage
    Réponses: 3
    Dernier message: 30/07/2008, 15h02
  2. Problème avec une fonction date.
    Par kmayoyota dans le forum ASP
    Réponses: 8
    Dernier message: 09/09/2004, 12h33
  3. Thread avec une fonction membre d'une classe
    Par SteelBox dans le forum Windows
    Réponses: 6
    Dernier message: 01/03/2004, 01h15
  4. Retourner une valeur avec une fonction
    Par stephtbest dans le forum ASP
    Réponses: 4
    Dernier message: 31/10/2003, 16h37
  5. [VBA-E] avec une fonction value
    Par laas dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 28/11/2002, 13h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo