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 :

Probleme avec une expression regulière


Sujet :

Python

  1. #1
    Candidat au Club
    Inscrit en
    Octobre 2007
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Octobre 2007
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Probleme avec une expression regulière
    Bonjour,

    dans un fichier html je veut remplacer tout les \n qui se trouve entre des balise td par <br/>.

    avec la lib re de python j'utilise cette commande:

    string=re.sub(r'(<td.*>.*)\n(.*</td>)',r'\1<br/>\2',string)

    mais ça ne marche pas.

    pouvez vous m'aider svp

  2. #2
    Membre averti Avatar de shell13010
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2008
    Messages
    281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Distribution

    Informations forums :
    Inscription : Mars 2008
    Messages : 281
    Points : 314
    Points
    314
    Par défaut
    salut

    Etant débutant je te propose quand meme ma reponse.

    peut etre avec un replace

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    a = '\n , <br/>'
    a.replace('\n','<br/>')
    Voila peut etre que sa pourra te servir.

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 053
    Points : 1 384
    Points
    1 384
    Par défaut
    donnes un exemple de string.
    sinon pas besoin de re pour remplacer des caracteres.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    string.replace('\n','</br>')
    arf, trop lent ...

  4. #4
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Ta RE marche s’il n’y a qu’un \n entre les deux balises:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    import re
    chaine = 'hop <td> orange \n dentelle </td> uu'
    print re.search(r'(<td.*>.*)\n(.*</td>)',chaine)
    print repr(re.search(r'(<td.*>.*)\n(.*</td>)',chaine).group())
    <_sre.SRE_Match object at 0x01918068>
    '<td> orange \n dentelle </td>'




    Mais si le motif que tu veux capturer comporte plusieurs \n , il faut permettre au point dans la regex de matcher avec les retours de lignes \n qui sont après le premier \n

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    chaine = 'hop <td> orange \n dentelle \n organdi \n capitule </td>'
    import re
    print re.search(r'(<td.*>.*)\n(.*</td>)',chaine)
    print re.search(r'(<td.*>.*)\n(.*</td>)',chaine,re.DOTALL)
    None
    <_sre.SRE_Match object at 0x016E2920>


    De plus il faut des ’?' pour stopper le caractère glouton de ’*’ .
    Sinon il se passe ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    chaine = 'hop <td> orange \n dentelle  </td>'\
             +'uu hhh uu ii<td> la grenouille verte </td> fin'
    import re
    print repr(re.search(r'(<td.*>.*)\n(.*</td>)',chaine).group())
    '<td> orange \n dentelle </td>uu hhh uu ii<td> la grenouille verte </td>'

    ------------------------------------------


    J’ai essayé de faire

    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
    ch = 'jeanjacques rousseau <td align="right"> diderot \n volt'\
         +'aire \nd\'alembert </td> russie oural kamatchaka '\
         +'saucisson <td> orangeraie \n dentelle\n andre breton\n </td> ocean'
     
    import re
     
    pat = re.compile('<td.*?>.*?</td>',re.DOTALL)
     
    def f(x):
        x = x.replace('\n','<br/>')
        return x
     
    print '\nle texte apres traitement :'
    w = pat.sub(f,ch)
    print w
    Mais ça coince à cause de l’utilisation de replace() , je ne saisis pas pourquoi.



    ------------------------------------


    Je fais donc autrement:

    Méthode avec (pos,cnt)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            li = [ (m.start(),m.group().count('\n')) for m in pat.finditer(ch0) ]
            ch = ch0
            allonge = 0
            for (pos,cnt) in li:
                ch = ch[0:pos+allonge] + ch0[pos:].replace('\n','</br>',cnt)
                allonge += cnt*(len('</br>')-len('\n'))
    et aussi

    Méthode avec (d,f)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            lo =  [ m.span() for m in pat.finditer(ch0) ]
            ch = ch0
            allonge = 0
            for (d,f) in lo:
                ch = ch[0:d+allonge] + ch0[d:f].replace('\n','</br>') + ch0[f:]
                allonge += ch0[d:f].count('\n')*(len('</br>')-len('\n'))
    EDIT

    Les 2 codes ci-dessus sont les corrections de ceux que j’avais mis précédemment et qui buggaient parce que je n’avais pas tenu compte du décalage introduit par tout remplacement de ’\n’ par ’</br>’ , ces deux chaînes ’\n’ et ’</br>’ étant de longueurs différentes.

    Pour rattraper les choses, il faut ajouter une valeur allonge qui s’accroît au fur et à mesure qu’on traite les portions matchantes.


    --------------

    J’ai par la suite pensé au code suivant qui, en faisant les modifications de la chaîne à partir de sa fin, ne présente pas le problème:


    Méthode avec (pos,cnt) rétrograde
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            li = [ (m.start(),m.group().count('\n')) for m in pat.finditer(ch0) ]
            ch = ch0
            for (pos,cnt) in li[-1::-1]:
                ch = ch[0:pos] + ch[pos:].replace('\n','</br>',cnt)
    Il se trouve que c'est le code le plus rapide des trois. Mais les écarts sont minimes.


    -----------------

    Dans les trois codes, les listes li et lo sont trouvées à partir d’expression régulière.
    Or en remplaçant ces méthodes par une méthode sans expression régulière utilisant à la place find() (méthode extrêmement rapide) pour trouver les positions voulues, on divise le temps par plus de 2.



    Méthode avec (pos,cnt) et find()
    qui fournit la même liste lo
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
            li = []
            pos = 0
            while 1:
                x = ch[pos:].find('<td')
                y = ch[pos:].find('</td>')
                if x+1:
                    li.append((x+pos,ch0[x:y].count('\n')))
                    pos += y + 5  # 5 = len('</td>'")
                else:
                    break


    ---------------


    Enfin, j’ai obtenu un truc G R A N D I O S E

    Méthode avec map() et enumerate()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import re
     
    ch = 'ju\nju <td align="right"> diderot \n voltaire \nfreron </td> rousseau russie'\
         +' oural kamatchaka \n siberie \n silesie\n'\
         +'pomme <td> orange \n dentelle\n mimosa\n organdi \n vetyver</td> ocean '\
         +'cabane en bois \n cheminee\n sagaie'
     
    pat = re.compile('(<td.*?>.*?</td>)',re.DOTALL)
    ch  = ''.join(map(lambda (i,u): [u,u.replace('\n','</br>')][i%2],enumerate(pat.split(ch))))
    print repr(ch)
    Quand j'ai fait le test avec map() et enumerate(pat.split(ch)) et que j'ai vu que map() venait de réussir à transformer l’objet enumerate(pat.split(ch)) avec la fonction fournie, j’ai été sou-ff-lé.

    Python, c’est quelque chose quand même

    J’aimerais bien voir ce que donne la résolution de ce problème écrit en C++ ou en Java.


    ------------------------------

    Deuxième EDIT ! :


    Je vais peut être finir par y arriver....

    J’ai pensé tester une méthode reposant aussi sur le découpage de la chaîne en une liste par split() selon le motif , mais sans utiliser ensuite enumerate() et map().

    Elle est un petit peu moins concise que la méthode avec map(enumerate()), mais elle gagne en lisibilité.


    Méthode simple avec split()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    L = re.compile('(<td.*?>.*?</td>)',re.DOTALL).split(ch)
    for i in xrange(1,len(L),2):
        L[i] = L[i].replace('\n','</br>')
    ch  = ''.join(L)
    Elle apparaît être seulement 10 % plus longue que la méthode la plus rapide avec (pos,cnt) et find() qui est elle même assez tarabiscotée.

    Je trouve que c’est finalement la meilleure:
    je préfère une méthode ramassée et très lisible à une méthode rapide et à une méthode acrobate. Le grandiose, c’est bien pour voir de quoi est capable Python, mais ce n’est pas le mieux.




    ------------------------------



    Programme comparatif des différentes méthodes

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    from time import clock
     
    ch0 = 'ju\nju <td align="right"> diderot \n voltaire \nfreron </td> rousseau'\
         +' \n russie \n siberie \n silesie\n'\
         +'pomme <td> orange \n dentelle\n mimosa\n organdi \n vetyver</td> ocean '\
         +'cabane en bois \n cheminee\n sagaie'
     
    import re
     
    pat = re.compile('(<td.*?>.*?</td>)',re.DOTALL)
     
    a=b=c=d=e=100000
    for k in xrange(30):
        if k%10==0:  print k,'  ',
     
     
        # Méthode avec (pos,cnt) et find()
        te = clock()
        for i in xrange(1000):
            liste_avec_find = []
            pos = 0
            while 1:
                x = ch[pos:].find('<td')
                y = ch[pos:].find('</td>')
                if x+1:
                    liste_avec_find.append((x+pos,ch0[x:y].count('\n')))
                    pos += y + 5  # 5 = len('</td>'")
                else:
                    break
            ch = ch0
            allonge = 0
            for (pos,cnt) in liste_avec_find[-1::-1]:
                ch = ch[0:pos] + ch[pos:].replace('\n','</br>',cnt)
        tf = clock()
        a = min(a,tf-te)
        boula = (ch==ch1)
        ch1 = ch
     
     
        # Méthode simple avec split()
        te = clock()
        for i in xrange(1000):
            L = re.compile('(<td.*?>.*?</td>)',re.DOTALL).split(ch)
            for i in xrange(1,len(L),2):
                L[i] = L[i].replace('\n','</br>')
            ch  = ''.join(L)
        tf = clock()
        b = min(b,tf-te)
        boulb = (ch==ch1)
     
     
        # # Méthode avec (pos,cnt) rétrograde
        te = clock()
        for i in xrange(1000):
            li = [ (m.start(),m.group().count('\n')) for m in pat.finditer(ch0) ]
            ch = ch0
            for (pos,cnt) in li[-1::-1]:
                ch = ch[0:pos] + ch[pos:].replace('\n','</br>',cnt)
        tf = clock()
        c = min(c,tf-te)
        boulc = (ch==ch1)
     
     
        # # Méthode avec (d,f)
        te = clock()
        for i in xrange(1000):
            lo =  [ m.span() for m in pat.finditer(ch0) ]
            ch = ch0
            allonge = 0
            for (d,f) in lo:
                ch = ch[0:d+allonge] + ch0[d:f].replace('\n','</br>') + ch0[f:]
                allonge += ch0[d:f].count('\n')*(len('</br>')-len('\n'))
        tf = clock()
        d = min(d,tf-te)
        bould = (ch==ch1)
     
     
     
        # Méthode avec (pos,cnt)
        te = clock()
        for i in xrange(1000):
            li = [ (m.start(),m.group().count('\n')) for m in pat.finditer(ch0) ]
            ch = ch0
            allonge = 0
            for (pos,cnt) in li:
                ch = ch[0:pos+allonge] + ch0[pos:].replace('\n','</br>',cnt)
                allonge += cnt*(len('</br>')-len('\n'))
        tf = clock()
        e = min(e,tf-te)
        boule = (ch==ch1)
     
     
        # Méthode avec split() , enumerate() et map()
        te = clock()
        for i in xrange(1000):
            ch  = ''.join(map(lambda (i,u): [u,u.replace('\n','</br>')][i%2],enumerate(pat.split(ch0))))
        tf = clock()
        f = min(f,tf-te)
        boulf = (ch==ch1)
     
     
     
    print
    print '\nMéthode avec (pos,cnt) et find() :\n',g(a)
    print '\nMéthode simple avec split() :\n',g(b),'=',str((b)*100/a)[0:6],'% de ',a,'   ch==ch1 est',boulb
    print '\nMéthode avec (pos,cnt) rétrograde :\n',g(c),'=',str((c)*100/a)[0:6],'% de ',a,'   ch==ch1 est',boulc
    print '\nMéthode avec (d,f) :\n',g(d),'=',str((d)*100/a)[0:6],'% de ',a,'   ch==ch1 est',bould
    print '\nMéthode avec (pos,cnt) :\n',g(e),'=',str((e)*100/a)[0:6],'% de ',a,'   ch==ch1 est',boule
    print '\nMéthode avec split() , enumerate() et map() :\n',g(f),'=',str((f)*100/a)[0:6],'% de ',a,'   ch==ch1 est',boulf

    Sur la base des minima obtenus sur plusieurs séries de tests:

    Méthode avec (pos,cnt) et find() :
    la plus rapide

    Méthode simple avec split() :
    109.62 % de 0.0813765436669 ch==ch1 est True

    Méthode avec (pos,cnt) rétrograde :
    136.45 % de 0.0813765436669 ch==ch1 est True

    Méthode avec (d,f) :
    136.80 % de 0.0813765436669 ch==ch1 est True

    Méthode avec (pos,cnt) :
    140.23 % de 0.0813765436669 ch==ch1 est True

    Méthode avec split() , enumerate() et map() :
    172.34 % de 0.0813765436669 ch==ch1 est True

Discussions similaires

  1. Probleme avec une expression reguliere-Replace
    Par BILLANT dans le forum VBScript
    Réponses: 1
    Dernier message: 02/07/2010, 09h39
  2. Réponses: 4
    Dernier message: 21/09/2008, 01h27
  3. [RegEx] probleme avec une expression reguliere
    Par SharKeR dans le forum Langage
    Réponses: 9
    Dernier message: 07/04/2006, 16h50
  4. au secour probleme avec une requete...
    Par soufiane59 dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 26/09/2003, 10h28
  5. probleme avec une division par zéro
    Par jcharleszoxi dans le forum Langage SQL
    Réponses: 2
    Dernier message: 26/03/2003, 18h14

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