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 :

[Biopython] Comment recuperer la taxonomie?


Sujet :

Python

  1. #1
    Membre régulier Avatar de Mydriaze
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    192
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 192
    Points : 95
    Points
    95
    Par défaut [Biopython] Comment recuperer la taxonomie?
    Bonjour à tous,

    J'ai un probleme bête (encore) d'expression réguliere ..

    Je veux parser un fichier genbank pour en recuperer entre autre la taxonomie.
    Or comme celle-ci se trouve sur plusieurs lignes les codes les autres codes ne marchent pas..

    Donc pour celui-là je recupere l'entree en XML .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            handle = Entrez.efetch(db = "Nucleotide", id=identifiant, rettype="xml")
            result = handle.read()
            print  result
    J'obtiens un truc du style :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    ...
     
                            </OrgName_mod>
                            <OrgName_lineage>Eukaryota; Metazoa; Arthropoda; Hexapoda; Insecta; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apis</OrgName_lineage>
                            <OrgName_gcode>1</OrgName_gcode> ...
    ....
    je voufrais recuperer tout ce qui est entre

    <OrgName_lineage> et </OrgName_lineage>


    J'essaye de faire qqch comme :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    taxonomie = (re.search("<OrgName_lineage>([\w\s\n]+)",result)).group(1)
    mais ça donne :

    ou


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    taxonomie = (re.search("<OrgName_lineage>([\w\s\n]+</OrgName_lineage>", result)).group(1)
    et ça donne

    AttributeError: 'NoneType' object has no attribute 'group'

    Je ne sais pas comment faire ...

    Est-ce que quelqu'un aurait une idee s'il vous plait?

    Merci ppar avance.

  2. #2
    Membre régulier Avatar de Mydriaze
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    192
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 192
    Points : 95
    Points
    95
    Par défaut
    Bon, je vous remercie !!!

    Vous avez resolu mon pb!

    En editant le poste je viens de voir que la taxonomie etait sur une seule ligne. le retour à la ligne etait reel qd je faisais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    handle = Entrez.efetch(db = "Nucleotide", id=identifiant, rettype="gb")
    Qd j'ai changé pour :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    handle = Entrez.efetch(db = "Nucleotide", id=identifiant, rettype="xml")
    j'avais le meme retour à la ligne mais à cause de la largeur de la console... lol

    donc ça venait juste du fait que je n'avais pas mis le ";" ds les expression reguliere..




    Maintenant j'ai tout bien !

    MERCI !!

  3. #3
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par Mydriaze Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
    taxonomie = (re.search("<OrgName_lineage>([\w\s\n]+</OrgName_lineage>", result)).group(1)
    C'est déjà plus proche de la solution que la première proposition

    La raison pour laquelle tu tombes sur cette erreur de "None has no attribute...", c'est parce que d'une part ta regex contient une erreur, et d'autre part qu'il se peut qu'elle ne match pas.

    Construisons cette regex:
    On a, comme tu l'as bien mis, "<OrgName_lineage>" et sa fermante de part et d'autre de la chaîne.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <OrgName_lineage></OrgName_lineage>
    Entre les deux, des caractères, des blancs, des passages à la ligne... bref un peu de tout, sauf une balise fermante. Tout sauf un "<" s'exprime en ces termes simples:
    En mettant un répétiteur derrière, ainsi que des parenthèses pour récupérer le groupe, ça nous amène à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <OrgName_lineage>([^<]+)</OrgName_lineage>
    Et voilà
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    # Autant ne compiler la regex qu'une fois, on gagnera du temps
    pattern = re.compile(r"<OrgName_lineage>([^<]+)</OrgName_lineage>")
     
    for item in pattern.findall(theXMLData):
        print item
    Edit: erf, l'auteur du post s'est aidé lui-même avant que je n'aie le temps de poster :p

  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
    À mon avis, il y a confusion.



    On peut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.compile(r"<OrgName_lineage>([^<]+)</OrgName_lineage>")
    seulement si l’on sait qu’il n’y a jamais de carcatère ’<’ dans le contenu de l’élément.

    Auquel cas, il est tout à fait identique d’écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.compile(r"<OrgName_lineage>([^<]+)<")
    Mais d’où vient cette restriction sur ’<’ ??





    Toutefois, on peut capter le contenu de l’élément sans se préoccuper de ce qui peut constituer ce contenu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.compile(r"<OrgName_lineage>(.+)</OrgName_lineage>")
    parce que le contenu de l’élément ne peut pas contenir la chaîne de sa balise fermante.....

    Mais on peut même écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.compile(r"<OrgName_lineage>(.+)<")
    parce que le répétiteur + est greedy = glouton: il va progresser au maximum dans la chaîne traitée pour ne s’arréter que devant la fin de chaîne ou devant un caractère newline. Bien sûr s’il va aussi loin, la RE "<OrgName_lineage>(.+)<" ne matchera pas
    ==> la plus grande chaîne qui matchera avec "<OrgName_lineage>(.+)<" sera celle qui s’arrêtera au dernier ’<’ dans la chaîne et c’est ce qui permet d’obtenir le résultat voulu.
    Résultat susceptible de contenir des ’<’ en son sein, cette fois.

    Mais il ne faut évidemment pas que le mode MULTILINE soit activé.

  5. #5
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par eyquem Voir le message
    On peut écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    re.compile(r"<OrgName_lineage>([^<]+)</OrgName_lineage>")
    seulement si l’on sait qu’il n’y a jamais de carcatère ’<’ dans le contenu de l’élément.
    XML requiert qu'il n'y ait pas ce caractère dans le texte. Il doit être remplacé par &lt;
    De plus, et tout le monde semble l'ignorer, les . (points) doivent être évités à tout prix dans les regex. Ils représentent tout simplement une source de bug et une catastrophe niveau performance.

  6. #6
    Membre régulier Avatar de Mydriaze
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    192
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2006
    Messages : 192
    Points : 95
    Points
    95
    Par défaut
    Rhoooo là là là ...21h16, 23h26, 23h56 ... Vous êtes graves les garçons.... lol

    Bon, en tout cas, Merci infiniment pour votre aide!!!

    Apparement il n'y aurait que des lettres, des chiffres, des espaces, le ";" , le "-" ... , (à priori pas de points?)
    ...

    Donc j'ai fini par ecrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    taxonomie = (re.search("<OrgName_lineage>([\w\s;-]+)",result3)).group(1)
    qui a marché . Il ne fallait pas oublier le ";" ... A partir de là , il prend tout jusqu'au "<" puisqu'il n'est pas ds la regex.

    Mais effectivement c'etait bien plus simple de mettre [^<] . Donc j'ai remplacé. et ça marche nickel ! MERCI !

    Par contre je ne compile jamais les regex. Je n'ai jamais compris à quoi ça servait ... apparemment ça marche bien sans ... enfin je crois...

  7. #7
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Oui, ça marche tout aussi bien sans.
    Quand tu fais une recherche "sans la compiler", elle est compilée en interne.
    Autrement dit, elle est compilée pour chaque recherche. Ca représente une perte de temps

  8. #8
    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
    J’ai pris l’habitude de distinguer RE et regex.
    Une RE est une chaîne qui sert à définir un objet “expression régulière“ compilé.
    regex est un tel objet compilé

    C’est en effet deux choses à bien distinguer, n’est ce pas. Or j’ai remarqué dans les docs, que l’abbréviation RE est toujours employée quand il est question d’une chaîne à compiler et que les quelques fois où la contraction regex ou Regex apparaît, c’est un objet ’expression régulière’ qui est évoqué.







    Intérêt de compiler une regex: uniquement dans le cas où une recherche par expression régulière avec une même RE est réalisée plusieurs fois dans un programme –-> rapidité du programme plus élevée

    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
    import re
    from time import clock
     
    ch = "h1n1_brr<hu&Aity998y che9m 3:::::897 ghrity,46kilo per=%% bn"
    RE = '\t*\w+<.{4}(i.?y) {0,12}[^123456]+.:+\d{3} ghr\\1[,"](?!8)\d+kil. +[eoirnp=x]{3,5}%.?% b[^r]'
     
    patX = re.compile(RE)
     
    n = 20
     
    te = clock()
    for i in xrange(n):
        x = re.match(RE,ch).group(1)
    tf = clock()
    print re.match(RE,ch).group(1)
    print 'avec compilation a la demande    :',tf-te
     
    t1 = clock()
    for i in xrange(n):
        x = patX.match(ch).group(1)
    t2 = clock()
    print patX.match(ch).group(1)
    print 'avec pre-compilation de la regex :',t2-t1,'....',str((t2-t1)*100/(tf-te))[0:5],'% de',tf-te
    ity
    avec compilation a la demande : 0.000683327070895
    ity
    avec pre-compilation de la regex : 0.000420723862952 .... 61.56 % de 0.000683327070895











    XML requiert qu'il n'y ait pas ce caractère dans le texte. Il doit être remplacé par &lt;
    Je ne savais pas, ou j’ai oublié.
    Dans ce cas particulier, on PEUT donc effectivement utiliser
    re.compile(r"<OrgName_lineage>([^<]+)")
    ....et non pas
    re.compile(r"<OrgName_lineage>([^<]+)<")
    comme je l’ai écrit, soit dit en passant. Le ’<’ ne sert à rien du tout dans le cas où on utilise [^<] !

    Et non seulement on peut, mais il est PREFERABLE de l’utiliser car Antoine935 a raison, des tests montrent que
    re.compile(r"<OrgName_lineage>([^<]+)")
    est plus rapide que
    re.compile(r"<OrgName_lineage>(.+)<")

    Le programme suivant montre que .+ prend environ 7 % de temps en plus que [^<]+ pour faire une détection.

    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
    from timeit import Timer
     
    ch = "h1n1_brr<hu&Aity998y che9m 3:::::897 ghrity,46kilo per=<"
     
    patA = re.compile('\t*\w+<([^<]+)')
    patB = re.compile('\t*\w+<(.+)<')
    patI = re.compile('\t*\w+<(.{4}(i.?y) {0,12}[^123456]+.:+\d{3} ghr\\2[,"](?!8)\d+kil. +[eoirnp=x]{3,5})<')
     
    tA = Timer('x = patA.match(ch).group(1)','from __main__ import patA,ch').repeat(5000,10)
    tB = Timer('x = patB.match(ch).group(1)','from __main__ import patB,ch').repeat(5000,10)
    tI = Timer('x = patI.match(ch).group(1)','from __main__ import patI,ch').repeat(5000,10)
     
    minA = min(tA)
    minB = min(tB)
    minI = min(tI)
     
    print 'avec [^%] dans RE :',minA
    print 'avec .+ dans RE   :',minB,'....',str(minB*100/minA)[0:6],'%'
    print 'avec RE detaillee :',minI,'....',str(minI*100/minA)[0:6],'%'
     
    resA = patA.match(ch).group(1)
    resB = patB.match(ch).group(1)
    resI = patI.match(ch).group(1)
    print 'resI == resA : ',resI==resA,'\nresI == resB : ',resI==resB
    avec [^%] dans RE : 0.000103644457603
    avec .+ dans RE : 0.000111466680821 .... 107.54 %
    avec RE detaillee : 0.000171250815399 .... 165.22 %
    resI == resA : True
    resI == resB : True
    J’exprime cela avec cette précision de 7 % parce que:

    - le programme prend comme bases de comparaison les temps minimaux, seuls représentatifs de la rapidité intrinsèque d’une fonction, c’est à dire quand des activités de l’ordinateur parasitent le moins l’exécution

    - la chaîne testée se termine par le signe d’arrêt de la regex : ’<’. En effet, plus il y a des caractères dans la chaîne testée après le caractère de fin de match , plus .+ prend du temps pour vérifier dans ces caractères subsidiaires que ’<’ n’y est pas, alors que [^<]+ arrête la regex dès que ce caractère est atteint lors de l’exploration (pour comprendre cela, il faut se représenter la manière dont un moteur de regex travaille)

    Par exemple, avec
    ch = "h1n1_brr<hu&Aity998y che9m 3:::::897 ghrity,46kilo per=<% bn"\
    +'kjwjkdhvcdidcucuhg8683t4 uohwedhciuedofiefefeeefedcjhkjkebbkjbc76hu3hge 4tuwhgeufy3giiuu38477474334ef'\
    +'jerifi347837yt8u3fbiwq7e687t8iuiudfsgtrtwerwet564634243rweffwfwert3wtwewgew wjreg wej wergjw yw y4545 etwwergg'\
    +'hwhchvqwjhgvgdhvljhqbwljhbdcljqhbwljlqjwljqwlkjqlwejedqlwkjedlqjweflqlifqifiu4iug3ifug3iugfiucg3ug3 ciuch3c'\
    +'jbwleqijhfligiugiufiquwheiefuhqiwhfiuqhiu4hyfiuqhiuhifuhqiuhfiquwhdiuqwijdbcciuqwhefjq; wjddhfvihwdfiwiifhoiqhw'
    les résultats deviennent:

    avec [^%] dans RE : 0.000103644457567
    avec .+ dans RE : 0.00108812712222 .... 1049.8 %
    avec RE detaillee : 0.000174323831629 .... 168.19 %
    resI == resA : True
    resI == resB : True


    Enfin bref:
    [^<]+ est mieux que .+
    Mais c'est parce qu'ici , c'est possible de l'employer.

    Warning aussi: il faut se méfier avec [^<] car s’il y a une newline dans la chaîne à capturer, il n’aura aucune influence, et on pourra donc capturer une instance de motif qui s’étalerait sur plusieurs lignes.




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



    Cependant, je me garderais bien d’être aussi définitif que toi, Antoine935, en matière de regex:
    les . (points) doivent être évités à tout prix dans les regex. Ils représentent tout simplement une source de bug et une catastrophe niveau performance.


    - À tout prix...
    ben, il y a des cas où ils sont la seule possibilité, non ? Dans le cas de l’élément XML ci-dessus, on peut certes ne pas utiliser un point, mais quand on veut attraper un motif qui ne contient aucune condition, on fait comment ? Introduire du traitement de chaîne ?

    - question performance, mon petit programme montre bien que la différence est très faible entre les deux méthodes, ce qui invalide le terme de catastrophe. Je pense qu’il y a performance mauvaise quand le codeur ne maîtrise pas les conditions d’emploi de ses outils, tu as raison sur ce.....point.

    Pour ce qui est des points, personnellement, je savais qu’il faut s’en méfier parce que:

    - tu l’avais déjà signalé dans un post, et je l’avais retenu

    - j’avais déjà fait des tests comparatifs dont j’ai retenu que plus une RE s’éloigne de l’expression d’une chaîne simple, càd plus elle contient de positions ayant une condition au lieu d’un caractère, plus la recherche sera longue. Et donc plus il y a de points dans une RE au lieu de caractèes explicites, plus la recherche sera longue.
    Cependant, il faut relativiser: il y a une question de complexité. Si on demande au moteur de regex de matcher des caractères avec une condition précise, ça peut être plus long que de lui dire: tu glisses sur tous les caractères sans te préoccuper de ce qu’ils sont; la condition étant après évidemment.

    J’ai un 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
    16
    17
    18
    19
    20
    21
    import re
    from timeit import Timer
     
    pat = re.compile('kilo\d+guepard')
    pit = re.compile('kilo.+guepard')
    pot = re.compile('kilo397539876453443524354343425536464443222234153guepard')
     
    ch = 'jhkhjh kilo397539876453443524354343425536464443222234153guepard mny'
     
    print pat.search(ch).group()
    print pit.search(ch).group()
    print pot.search(ch).group()
     
    u = Timer('x = pat.search(ch)','from __main__ import pat,ch').repeat(200,20)
    v = Timer('x = pit.search(ch)','from __main__ import pit,ch').repeat(200,20)
    w = Timer('x = pot.search(ch)','from __main__ import pot,ch').repeat(200,20)
     
     
    print 'kilo\d+guepard.......',str(min(u))[0:10]
    print 'kilo.+guepard........',str(min(v))[0:10]
    print 'kilo397..153guepard..',str(min(w))[0:10]
    kilo397539876453443524354343425536464443222234153guepard
    kilo397539876453443524354343425536464443222234153guepard
    kilo397539876453443524354343425536464443222234153guepard
    kilo\d+guepard....... 0.00021231
    kilo.+guepard........ 0.00017823
    kilo397..153guepard.. 0.00010923

    Par contre [^<]+ et .+ ne présentent pas une grande différence: “tout sauf ’<’ “ n’est pas foncièrement différent de “tout sauf une newline“. Seul un test permet de voir que c’est le premier qui est plus rapide que le second, et ça je ne sais pas pourquoi......





    Pour ce qui est des points comme source de bug, c’est vrai. Mais c’est encore une fois quand le codeur ne se méfie pas assez et ne tient pas assez compte de certaines subtilités.





    Tout ceci étant à prendre avec prudence et esprit critique , parce que le domaine des expressions régulières est assez casse-gueule. D'où la nécessité de tester avec des programmes.



    PS
    Et si les mesures de temps étaient variables en fonction de l’ordinateur, perturbant ainsi les résultats comparatifs ?
    Allez savoir avec les regex.
    Si c’est le cas, suis intéressé d’en être informé. Merci

  9. #9
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Citation Envoyé par eyquem Voir le message
    J’ai pris l’habitude de distinguer RE et regex.
    Une RE est une chaîne qui sert à définir un objet “expression régulière“ compilé.
    RE signifie simplement Regular Expression, tout comme regex ou regexp.
    Il n'y a donc aucune différence entre les deux.re.compile(r"<OrgName_lineage>([^<]+)")
    est plus rapide que
    re.compile(r"<OrgName_lineage>(.+)<")
    La raison à cela est simple: le . (point) match tout. Ca signifie que la regex va aussi matcher le "</OrgName_lineage>" et tout ce qui reste dans le texte avant d'arriver à la fin et de se rendre compte qu'il ne peut pas matcher.
    Alors il revient un caractère en arrière, et se rend compte qu'il ne peut pas matcher. Alors il revient encore un caractère en arrière, pour se rendre compte à nouveau qu'il ne match pas. Et ainsi de suite jusqu'à ce que ça match. Bref, ça peut vite devenir la catastrophe.

    Ton exemple minimise la casse. Mais sur un string de plusieurs milliers de caractères de long avec une regex un rien plus compliquée, ça peut vite devenir un massacre.

    Warning aussi: il faut se méfier avec [^<] car s’il y a une newline dans la chaîne à capturer, il n’aura aucune influence, et on pourra donc capturer une instance de motif qui s’étalerait sur plusieurs lignes.
    Oui, mais dans le cas présent, on veut prendre tout ce qu'il y a entre les balises <OrgName_lineage> et sa fermante. Ca inclut donc les multilignes.

    À tout prix...
    ben, il y a des cas où ils sont la seule possibilité, non ? Dans le cas de l’élément XML ci-dessus, on peut certes ne pas utiliser un point, mais quand on veut attraper un motif qui ne contient aucune condition, on fait comment ? Introduire du traitement de chaîne ?
    Un point tout seul ne représente pas un souci en soi. Un point affecté par un opérateur de répétition devrait toujours être évité.

    - question performance, mon petit programme montre bien que la différence est très faible entre les deux méthodes, ce qui invalide le terme de catastrophe. Je pense qu’il y a performance mauvaise quand le codeur ne maîtrise pas les conditions d’emploi de ses outils, tu as raison sur ce.....point.
    Comme dit plus haut, le problème est exponentiel (et non linéaire) par rapport à la longueur de la chaîne. Sur des chaînes courtes ce n'est pas grave. Sur plusieurs milliers de caractères c'est dangereux.

    Pour ce qui est des points comme source de bug, c’est vrai. Mais c’est encore une fois quand le codeur ne se méfie pas assez et ne tient pas assez compte de certaines subtilités.
    J'ai une courte expérience, mais j'ai déjà appris à éliminer toutes les sources de bug possible. Il y en a toujours une que tu oublies et qui te pose problème. Donc plus il y a de risques de bug, plus...

    PS
    Et si les mesures de temps étaient variables en fonction de l’ordinateur, perturbant ainsi les résultats comparatifs ?
    Allez savoir avec les regex.
    Si c’est le cas, suis intéressé d’en être informé. Merci
    Je ne pense pas que les performances soient fortement affectées selon l'architecture de l'ordinateur. Ce ne sont que des caractères après tout.
    Par contre, il existe de nombreux moteurs de regex, certains plus rapides, d'autres plus flexibles, et d'autres qui font les deux
    Je ne serais pas étonné que l'unicode affecte également fortement les performances, mais je n'ai aucune info précise sur le sujet.

  10. #10
    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
    RE signifie simplement Regular Expression, tout comme regex ou regexp.
    Noooooon ??!






    Dans
    Il n'y a donc aucune différence entre les deux.re.compile(r"<OrgName_lineage>([^<]+)")
    est plus rapide que
    re.compile(r"<OrgName_lineage>(.+)<")
    La phrase Il n'y a donc aucune différence entre les deux. n’est pas de moi.

    Justement si, il y a une différence, c’est bien ce que j’ai pointé. Cette différence existe même quand la chaîne testée n’exacerbe pas le défaut de re.compile(r"<OrgName_lineage>(.+)<")

    J’ai bien vu que ce “défaut“ est que '(.+)<' cherche dans une chaîne après le premier ’<’ rencontré , alors que '[^<]+' s’arrête.



    J’ai donc bien fait attention dans le code (le second) de prendre une chaîne ch qui se termine par un seul et unique ’<’ dans toute la chaîne.

    J’estime donc que le résultat de ce code, qui montre un temps 7 % plus grand pour '(.+)<' que pour '([^<])' , démontre une rapidité INTRINSÈQUE de ([^<]) plus grande.

    Quand je dis intrinsèque, cela veut dire que c’est sans défavoriser '(.+)<' puisque la chaîne utilisée n’a pas de suite après le caractère ’<’: il s’agit de comparer des choses comparables, c’est pour éviter que '(.+)<' perde du temps à tester « tout ce qui reste dans le texte avant d'arriver à la fin et de se rendre compte qu'il ne peut pas matcher. » Cela je l’ai bien compris, et je croyais avoir été clair.



    Quand tu parles du ralentissement occasionné par "</OrgName_lineage>" , c’est le cas concret qui occupait Mydriase, ça ne correspond pas à ce que je disais à partir du code que j’ai avancé. C’est vrai que ça va rajouter un petit temps supplémentaire, mais à mon avis c’est un pouyème quasi négligeable.

    Ce n’est pas ce pouyème qui justife le plus de choisir plutôt '([^<]+)' . Pour moi c’est parce que ce dernier motif dans la RE est intrinsèquement meilleur. On dit la même chose, mais pas sur le même argument.

    Bien sûr, c’est bien de prévenir sur le danger de '.+' dans les regex. Mais il faut savoir de quoi on parle. Ce qui m’intéressait c’est la différence intrinsèque entre '[^<]+' et '.+<' dont je ne vois pas la raison.










    Je crois que tu es trop polarisé sur le danger attaché à un déterminant de répétition non bridé par '?'

    sur un string de plusieurs milliers de caractères de long avec une regex un rien plus compliquée, ça peut vite devenir un massacre.
    Ce n’est vrai que pour un déterminant non modulé par ? , c’est à dire quand on ne brime pas le caractère glouton des déterminants + et *. C’est seulement dans ce cas que le moteur de regex peut s’emballer en cherchant sur des milliers de caractères.

    Un point tout seul ne représente pas un souci en soi. Un point affecté par un opérateur de répétition devrait toujours être évité.
    Ce n’est pas toujours vrai. Je pense que “Un point affecté par un opérateur de répétition + ’?' “ est normalement envisageable.

    En fait il faut distinguer deux cas d’utilisation du point:
    - sans modérateur ’?’ , c’est ce dont j’ai parlé plus haut;
    - et avec le coupe-faim ’?’

    Ce deuxième cas présente encore des variations en fonction de la longueur du motif d’arrêt. S’il s’agit de faire arrêter le moteur de retgex à un caractère unique (comme ci-dessus ’<’ ), ce sera plus rapide que de le faire arrêter sur un motif de 2 caractères.... Mais pour 2,3,4 etc caractères d’arrêt le temps de vérification ne croît pas linéairement car s’il faut trouver un motif de 8 caractères par exemple, le moteur de regex aura rarement à vérifier jusqu’au 8ième caractère pour constater qu’une portion de 8 caractères ne matche pas....
    Bon c’est un peu fuligineux à expliquer


    En tous cas, c’est avec l’intention de traiter le cas ’point . non glouton’ que j’ai exhibé un code qui devait mettre en évidence le comportement de '.+' dans une recherche stoppée à la première occasion.

    Dans ce code, la comparaison de '\d+' et '.+' montre un avantage de '.+'
    MAIS JE ME SUIS TROMPÉ: j’aurais dû écrire
    re.compile('kilo.+?guepard')
    et non pas re.compile('kilo.+guepard')
    Ça ne porte pas à conséquence en réalité parce que la chaîne testée n’a pas une queue étendue après le motif ’guépard’. Justement.

    Mais surprise ! En testant avec la correction , il sort un résultat auquel je ne m’attendais pas :

    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
    import re
    from timeit import Timer
     
    pat = re.compile('kilo\d+guepard')
    pit = re.compile('kilo.+guepard')
    pit2 = re.compile('kilo.+?guepard')
    pot = re.compile('kilo397539876453443524354343425536464443222234153guepard')
     
    ch = 'jhkhjh kilo397539876453443524354343425536464443222234153guepard mny'
     
    print pat.search(ch).group()
    print pit.search(ch).group()
    print pit2.search(ch).group()
    print pot.search(ch).group()
     
    u = Timer('x = pat.search(ch)','from __main__ import pat,ch').repeat(200,20)
    v = Timer('x = pit.search(ch)','from __main__ import pit,ch').repeat(200,20)
    v2 = Timer('x = pit2.search(ch)','from __main__ import pit2,ch').repeat(200,20)
    w = Timer('x = pot.search(ch)','from __main__ import pot,ch').repeat(200,20)
     
     
    print 'kilo\d+guepard.......',str(min(u))[0:10]
    print 'kilo.+guepard........',str(min(v))[0:10]
    print 'kilo.+?guepard........',str(min(v2))[0:10]
    print 'kilo397..153guepard..',str(min(w))[0:10]
    kilo397539876453443524354343425536464443222234153guepard
    kilo397539876453443524354343425536464443222234153guepard
    kilo397539876453443524354343425536464443222234153guepard
    kilo397539876453443524354343425536464443222234153guepard
    kilo\d+guepard....... 0.00022321
    kilo.+guepard........ 0.00018801
    kilo.+?guepard........ 0.00033216
    kilo397..153guepard.. 0.00010923
    '.+?' est 80 % plus long que '.+'

    Ce qui du coup le rend plus lent que le motif '\d+' , contrairement à '.+' qui était plus rapide que '\d+' .

    Conclusion: la présence du restricteur '?' alourdit la regex. Les expressions régulières présentent décidémment bien des méandres surprenants.








    Bon, je commence à fatiguer avec ces regex capricieuses.
    J’en arrive à ceci (provisoirement):

    - l’utilisation de ’.+motif’ sur une chaîne dans laquelle il n’y a pas des milliers de caractères après le motif d’arrêt n’est pas à trop redouter pour ce qui est de la rapidité.
    C’était utilisable dans le cas de Mydriase avec une bonne performance, mais je préfère le ’[^<]+’, autre solution qui n’est possible à mon avis que parce qu’il n’y a qu’un caractère à complémenter.
    Quant à un bug, je ne vois pas trop quel genre.

    - l’utilisation de ’.+motif’ dans d’autres cas, est dangereuse si on n’est pas prévenu: il y a risque sérieux de bug ou de temps d’exécution très long

    - l’utilisation de ’.+?motif’ ne prête pas trop le flanc à un bug. Mais il faut savoir que c’est plus long que ’.+motif’, et si la section à détecter n’est pas courte, ça peut se faire sentir. Par contre pour un chaîne courte, 20 caractères disons, je ne vois pas trop le problème que ça pose en terme de temps


    J’aimerais que tu donnes des exemples de bugs qui ne relève pas de la deuxième catégorie de cette rapide classification. Tu devrais bien en avoir sous la main, d’aprés ce que tu dis.






    Je ne pense pas que les performances soient fortement affectées selon l'architecture de l'ordinateur. Ce ne sont que des caractères après tout.
    J'évoquais ça au cas où mes considérations seraient invalidées par des résultats relatifs différents sur d’autres machines.
    J’aimerais avoir des mesures concrètes réalisées avec mes codes sur d’autres machines.





    Par contre, il existe de nombreux moteurs de regex, certains plus rapides, d'autres plus flexibles, et d'autres qui font les deux
    Je serai intéressé par de plus amples informations sur ce sujet.






    Je ne serais pas étonné que l'unicode affecte également fortement les performances
    Y a qu’à tester

  11. #11
    Membre éprouvé
    Avatar de Antoine_935
    Profil pro
    Développeur web/mobile
    Inscrit en
    Juillet 2006
    Messages
    883
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur web/mobile

    Informations forums :
    Inscription : Juillet 2006
    Messages : 883
    Points : 1 066
    Points
    1 066
    Par défaut
    Oula, on a du mal se comprendre sur certains points... car je t'ai prêté des paroles que tu n'as pas eues

    D'autre part, je n'ai pas souvenir d'avoir parlé d'un "ralentissement occasionné par "</OrgName_lineage>" "
    bref...

    Ce qui m’intéressait c’est la différence intrinsèque entre '[^<]+' et '.+<' dont je ne vois pas la raison.
    Eh bien, c'est justement qu'avec le premier, il s'arrêtera dès qu'il rencontrera le '<'. Avec le second, il passe au dessus, avant d'y revenir par après.

    Je crois que tu es trop polarisé sur le danger attaché à un déterminant de répétition non bridé par '?'
    Oui, c'est possible

    Conclusion: la présence du restricteur '?' alourdit la regex.
    Si mes souvenirs sont justes, quand tu donnes au moteur de regex un pattern du style .+?abc, il va à chaque fois essayer de matcher a, puis ab, puis abc. S'il échoue à un de ces essais, il essaye de matcher avec le caractère répété en non-greedy (soit ici le point). Il fait de même, bien sur, pour le caractère suivant. C'est la raison pour laquelle c'est plus lent.

    - l’utilisation de ’.+?motif’ ne prête pas trop le flanc à un bug. Mais il faut savoir que c’est plus long que ’.+motif’, et si la section à détecter n’est pas courte, ça peut se faire sentir. Par contre pour un chaîne courte, 20 caractères disons, je ne vois pas trop le problème que ça pose en terme de temps
    Comme expliqué plus haut, ce n'est pas seulement la longueur de la chaîne qu'il faut prendre en compte, mais la regex elle-même.

    J’aimerais que tu donnes des exemples de bugs qui ne relève pas de la deuxième catégorie de cette rapide classification. Tu devrais bien en avoir sous la main, d’aprés ce que tu dis.
    Parlons plutôt d'erreur de programmation, puisque les moteurs de regex ne souffrent en général pas de bugs.
    J'avoue que je n'en ai pas trop sous la main, mais j'ai souvenir de bizarreries sous certains moteurs (était-ce PERL ou PCRE ?).
    Un pattern du style hello.+< ne matcherait pas contre hello223<. Je n'ai ni PERL ni un PCRE sous la main pour tester, mais je suis quasiment certain de ce point.

    Je serai intéressé par de plus amples informations sur ce sujet
    Le plus en vogue actuellement est le moteur PCRE (Perl Compatible Regular Expression): http://www.pcre.org/
    Il est utilisé par PHP notamment, avec la famille des fonctions preg_* (ou plutôt preg_[\w_]+ puisqu'on parle de regex :p )
    Le premier moteur de regex (enfin premier... pas sur, mais le premier digne de ce nom), et précurseur de pas mal de fonctionnalités est celui de PERL.
    Un autre disponible et très puissant est celui de Java.
    Je pense bien que ces trois moteurs sont actuellements les plus puissants, avec peut-être celui de .NET pas loin. Ils offrent notamment le look-ahead et look-behind, des possibilités un peu difficiles à maîtriser, mais extrèmement puissantes.

    Existe aussi celui de Python, plus basique hélas... Il existe aussi les regex POSIX (en PHP, la famille ereg), fort utilisée en shell linux.
    Il doit certainement exister pleins d'autres moteurs, mais je ne les connais pas tous.

    Je testerai peut-être demain tes codes sur ma machine, histoire de faire ces fameux tests. L'unicode y passera certainement aussi.


    Oh, petit coup de pub en passant pour un de mes logiciels :p Si vous bossez sur les regex, ce sera votre ami !
    http://www.aspyct.org/doku.php?id=lurt

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 5
    Dernier message: 17/06/2005, 17h17
  2. Réponses: 3
    Dernier message: 04/02/2004, 19h35
  3. Réponses: 2
    Dernier message: 19/01/2004, 13h19
  4. comment recuperer le nom des champs ?????
    Par e11137 dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 09/01/2004, 11h00
  5. comment recuperer une variable dans flash
    Par krépuscul dans le forum Flash
    Réponses: 30
    Dernier message: 16/10/2003, 10h40

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