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 :

regexp python extraire


Sujet :

Python

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut regexp python extraire
    Bonjour,
    j'ai un ensemble de chaine qui ressemble à ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    %{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}
    %{I,i.N+z1:ms:mp}
    %{DANS,dans.PREP+Dnom+z1}
    %{LEQUEL,lequel.DET+'Dnom'+z1:ms}
    %{si,.CONJS+z1}
    %{se,.PRO+PpvLE+z1:3fs:3ms:3fp:3mp}
    %{ACCEPTENT,accepter.V+z1:P3p:S3p}
    j'aimerai récupérer 3 mots :

    Chapitre puis Chapitrer puis V
    I puis i puis N
    DANS dans PREP

    En fait je cherche à recupérer les mots après le { puis entre la , et . et le mot juste après .

    avez vous une idée d'expression régulière ?

    merci

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    c cool , j'ai réussi avec la doc, à faire une regexp

    pour info si un jour ça sert à qqn :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    t = "%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}"
    m = re.search(r"(\w+)\,(\w+).(\w+)", t)

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    salut, je te déconseil d'utiliser les \w et autres dont tu ne maitrise pas forcément le contenu.
    Surtout en matière de TAL, où tu vas vite te retrouver confronté à des problèmes avec les lettres accentuées etc.
    Essaie plutôt de te créer tes propres groupes en définissant des variables :
    par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ponctuation = 'u'[ \'"«»\#\.\?,;:!\(\)\[\]\|]+''
    Ou alors, il faut utilser la définition de LOCALE qui te permet de spécifier l'encodage utilisé sur ta machine et donc ce à quoi correspond exactement \w.
    De toutes les manières, dans ton cas, le plus simple consiste à utilser le . puisque ce que tu veux, c'est tout entre le { et la , puis entre la , et le .

    D'autre part, si ta virgule n'a pas besoin d'être backslashée, ce n'est pas le cas de ton point. Tu aurais donc plutôt dû faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m = re.search(r"(\w+),(\w+)\.(\w+)", t)
    Ensuite, évite les opérateurs gourmand comme tu le fais. En effet, par défaut, les expressions régulières cherchent la solution la plus longue possible.
    Il vaut mieux utiliser les opérateurs + et * avec ? (.+? ou .*?), ce qui signifie que tu cherches le plus petit groupe matchant ton expression.

    Pour finir, compile plutôt tes motifs de recherche. Les expressions régulières ne sont pas particulièrement efficaces de manières générales (une expression régulière simple comme la tienne mets 5 à 10 fois plus de temps à obtenir un résultat qu'une recherche avec des find et des extractions de chaine). Alors si en plus tu ne les compiles pas, ça peut devenir l'horreur.
    Pour compiler, c'est simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    t = "%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}"
    motif = "(\w+),(\w+)\.(\w+)"
    motifCompile = re.compile(motif)
    reponse = re.search(motifCompile, t)
    En définitive, le code est un peu plus long, mais mieux maîtrisé et plus efficace. Dans ton cas, j'aurais écrit tes deux lignes de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        motif = '(.+?),(.+?)\.(.+?)\+'
        motifCompile = re.compile(motif)
     
        t = "%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}"
        m = re.search(motifCompile, t)
    voilà, bonne chance avec tout ça, tu verras que les expressions régulières deviennent vite des usines à gaz mais qu'elles sont quand même très pratiques de manière générale.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    PS :

    avec ton expression, sur la chaine %{si,.CONJS+z1} tu ne récupère rien alors qu'avec des * à la place des + tu aurais eu si, rien, CONJS comme réponse.

    => m = re.search(r"(\w*),(\w*)\.(\w*)", t)

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    PS 2 : je ne sais pas quel analyseur donne ce genre de sorties mais il me semble bizare que Chapitre soit considéré comme la forme fléchie de Chapitrer et non comme un nom commun !

  6. #6
    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
    Je suis entièrement d'accord avec cyrull sur tous ses points. Je n'ai pas eu le courage de les écrire.
    Et particulièrement sur celui-ci dont je me suis aperçu avec la pratique:
    «une expression régulière simple comme la tienne mets 5 à 10 fois plus de temps à obtenir un résultat qu'une recherche avec des find et des extractions de chaine»

    J'ajoute juste une chose : l'utilisation du mot commun groupe dans les regex porte à se méprendre sur la fonction réelle des parenthèses délimitant des groupes dans les regex.
    Ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    motif = '.+?,.+?\..+?\+' 
    #va produire le même résultat que 
    motif = '(.+?),(.+?)\.(.+?)\+' 
    #sur la chaine 
    t = "%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}"
    dans le code que tu donnes en exemple, cyrull.
    Il ne faut pas se laisser tromper par l'apparente bizarrerie de la succession \.. en l'absence de parenthèses.
    J'espère enfoncer une porte ouverte, mais je ne suis pas sûr que ce soit le cas....

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    PS 2 : je ne sais pas quel analyseur donne ce genre de sorties mais il me semble bizare que Chapitre soit considéré comme la forme fléchie de Chapitrer et non comme un nom commun !
    ça vient du logiciel Unitex.
    Mais merci pour toutes vos remarques !!!

    c'est vrai que les expressions régulières ça devient vite lourd, mais parfois, ça aide bien !!

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    à mon avis, elles doivent être utilisée pour modeliser les choses, mais dès lors qu'il faut rendre le résultat efficace (en TAL, on a vite des corpus en centaine de millier de mots), il n'est plus question de faire autrement qu'avec les fonctions de string.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    motif = '.+?,.+?\..+?\+' 
    #va produire le même résultat que 
    motif = '(.+?),(.+?)\.(.+?)\+' 
    #sur la chaine 
    t = "%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}"
    dans le code que tu donnes en exemple, cyrull.
    Il ne faut pas se laisser tromper par l'apparente bizarrerie de la succession \.. en l'absence de parenthèses.
    J'espère enfoncer une porte ouverte, mais je ne suis pas sûr que ce soit le cas....
    ça ne va pas donner tout à fait le même résultat. En effet, sans les parenthèses, tu ne peux que récupérer le résultat de l'expression entière via un m.group(0) alors qu'avec les parenthèses, m.group(0) donne le même résultat, mais tu as en plus accès à m.group(1), m.group(2) ... correspondant à chacunes de tes parenthèses.
    Ton expression ne peut donc ramener que {Chapitre,chapitrer.V+ alors que la mienne va pouvoir te donner le même résultat ou alors Chapitre pour m.group(1), chapitrer pour m.group(2) et V pour m.group(3) ce qui doit beaucoup correspondre à ta volonté initiale.

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    pour être complet, dans ton cas, un code du type suivant serait plus simple à exploiter :

    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
    # -*- coding: cp1252 -*-
    import re
     
    motif = '{(.+?),(.+?)\.(.+?)\+'
    motifCompile = re.compile(motif)
     
    t = '''%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}
    %{I,i.N+z1:ms:mp}
    %{DANS,dans.PREP+Dnom+z1}
    %{LEQUEL,lequel.DET+'Dnom'+z1:ms}
    %{si,.CONJS+z1}
    %{se,.PRO+PpvLE+z1:3fs:3ms:3fp:3mp}
    %{ACCEPTENT,accepter.V+z1:P3p:S3p}
    '''
     
    m = re.findall(motifCompile, t)
     
    print m
    m sera alors la liste de tuples suivante :
    [('Chapitre', 'chapitrer', 'V'), ('I', 'i', 'N'), ('DANS', 'dans', 'PREP'), ('LEQUEL', 'lequel', 'DET'), ('ACCEPTENT', 'accepter', 'V')]

  11. #11
    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
    On est bien d'accord, cyrull.
    En fait, je n'avais pas fait bien attention à ce que cherchait ekremy (il parait que ce qu'on trouve est plus important que ce qu'on cherche uhuh) (en regardant, je vois qu'il ne dit d'ailleurs pas sous quelle forme il veut obtenir ses 3 mots: liste, tuple, chaine, dico ?)
    J'ai pensé à la va-vite chercher toutes les chaines situées entre { et + et les traiter ultérieurement en fonction du besoin.
    Étant dans le même esprit que toi par rapport aux regex, je pensais ainsi qu'utiliser le motif '{.+?,.+?\..+?\+' au lieu du motif '{(.+?),(.+?)\.(.+?)\+' allégerait le travail de la regex.

    Mais c'est plus vite pensé que fait. Concrétement si on veut spliter les chaines obtenues, il faut à nouveau utiliser une fonction de re puisqu'il y a deux séparateurs, ou une autre astuce, et comme le fonctionnement de findall produit un résultat différent quand il n'y a pas de groupes définis dans le motif, je suis obligé de rajouter des lookaround assertion pour ne pas trainer { et + dans les chaines extraites.
    C'est amusant aussi, et avec des list comprehension ça passe mieux, mais c'est lourdingue quand même:
    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
    # -*- coding: cp1252 -*-
    import re
    t = '''%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}
    %{I,i.N+z1:ms:mp}
    %{DANS,dans.PREP+Dnom+z1}
    %{LEQUEL,lequel.DET+'Dnom'+z1:ms}
    %{si,.CONJS+z1}
    %{se,.PRO+PpvLE+z1:3fs:3ms:3fp:3mp}
    %{ACCEPTENT,accepter.V+z1:P3p:S3p}
    '''
    resa = [ re.split(',|\.',u)\
             for u in re.findall('(?<={).+?,.+?\..+?(?=\+)', t) ]
     
    resb = [ w.replace(',','.').split('.')\
             for w in re.findall('(?<={).+?,.+?\..+?(?=\+)', t) ]
     
    print resa,'\n\n',resb
    S'il tient à utiliser une regex, ta méthode avec findall() et ton motif convient beaucoup mieux.


    Sinon je suis du même avis que toi: dans un cas pareil je me passerais de regex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # -*- coding: cp1252 -*-
    t = '''%{Chapitre,chapitrer.V+z2:P1s:P3s:S1s:S3s:Y2s}
    %{I,i.N+z1:ms:mp}
    %{DANS,dans.PREP+Dnom+z1}
    %{LEQUEL,lequel.DET+'Dnom'+z1:ms}
    %{si,.CONJS+z1}
    %{se,.PRO+PpvLE+z1:3fs:3ms:3fp:3mp}
    %{ACCEPTENT,accepter.V+z1:P3p:S3p}
    '''
    print [ u[2:].partition('+')[0].replace(',','.').split('.')\
            for u in t.splitlines() ]

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Février 2009
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 13
    Points : 11
    Points
    11
    Par défaut
    oups, grand observateur que je suis, je n'avais pas vu que j'avais 2 interlocuteurs. Désolé Eyquem. Je pensais que tu étais ekremyilmaz et que tu tatonnais.
    Et nous sommes effectivement d'acord sur les expressions régulières.
    Il n'y a qu'un truc que je n'ai pas testé : l'efficacité du findall par rapport aux fonctions de string tant que l'expression régulière reste simple.
    En effet, dans ce cas là, il faut compter à la fois le temps de recherche et le temps de stockage des réponses.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    99
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 99
    Points : 102
    Points
    102
    Par défaut
    Je vais juste me permettre d'ajouter une chose quand à l'utilisation du re.compile() des expression régulières.

    Je pense que les deux experts maitrises bien le sujet et sont au courant mais la façon dont cela a été dit plus haut peu prêter à confusion. A savoir qu'une regexp sera forcement compilée, et ce qu'ait été appelé re.compile() de façon explicite ou pas.
    Dans le cas d'un appel direct a re.search(pattern, string) le déroulement ce fait en 2 phase:
    1. Compiler le pattern de l'expression régulière.
    2. Faire la recherche des résultats.


    Le gain en temps CPU de la fonction compile vient du fait que l'on cherche souvent à appliquer la même expression régulière à plusieurs chaines de caractères et que dans le cas ou l'on va réutiliser le résultat de "re.compile", la première phase va pouvoir être sauter pour ne faire que la 2ème partie.
    Ainsi l'expression ne sera compilée qu'une unique fois au lieu de le faire à chaque fois que l'on va faire une recherche.

    On voit même dans la doc une note assez intéressante :
    Note: The compiled versions of the most recent patterns passed to re.match(), re.search() or re.compile() are cached, so programs that use only a few regular expressions at a time needn’t worry about compiling regular expressions.
    Ou le gain de re.compile() se voit encore plus restreint puisque le caching du résultat se fait automatiquement dans certains cas. Mais les 'certains cas' restent à être analysés et définies précisément.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 04/01/2013, 21h13
  2. [Syntaxe ?] Regexp en Python
    Par Thomus38 dans le forum Général Python
    Réponses: 1
    Dernier message: 21/08/2007, 14h43
  3. Regexp: extraire du texte entre deux balises
    Par moook dans le forum Langage
    Réponses: 11
    Dernier message: 19/06/2007, 18h08
  4. [RegExp] Extraire le texte entre 2 balises
    Par d1g-2-d1g dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 27/02/2007, 19h15
  5. extraire chiffre avec regexp
    Par chillansky dans le forum ASP
    Réponses: 1
    Dernier message: 17/08/2006, 10h28

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