Forum Programmation.autre Expression régulière

Posté par . Licence CC by-sa
Tags : aucun
1
18
oct.
2013

Bonjour forum,

Pourrais-tu m'aider à comprendre pourquoi les deux expressions régulières ci-dessous ne font pas la même chose ? Au départ j'ai pensé à la version commentée et je ne comprend pas pourquoi elle ne marche pas.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
text = "plop\n<salut\nplop\n>"

#m = re.search('<salut[.\\n]*>', text)
m = re.search('<salut(.|\\n)*>', text)

if m == None:
    print "Motif introuvable"
else:
    print m.group(0)

Danke schön

  • # réponse un peu idiote peut être

    Posté par (page perso) . Évalué à 2.

    les [ ] fabriquent un groupe de possible à trouver
    les ( ) fabriquent un groupe à capturer ?

  • # Caractères spéciaux dans [ ]

    Posté par (page perso) . Évalué à 6.

    Dans les classes [ ], le « . » perd sa signification spéciale, et signifie vraiment un point littéralement, du moins en perl, d'où ton problème je pense. Remarque, c'est logique car c'est rare que dans une classe entre crochets on veuille que ça matche plus que le « . » au sens spécial.

    • [^] # Re: Caractères spéciaux dans [ ]

      Posté par . Évalué à 0.

      Non, c'est le \n qui pose problème. Le "." n'en pose pas.

    • [^] # Re: Caractères spéciaux dans [ ]

      Posté par . Évalué à 1.

      Au temps pour moi.
      Après avoir un peu mieux réfléchis je crois bien que tu as raison :-)

      Ce que j'ai testé pour m'en convaincre c'est de remplacer le . par a-z dans les crochets et ça matche bien la même chose que l'expression avec les parenthèses.

      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      import re
      text = "plop\n<salut\nplop\nplop\n>plop\n>"
      
      mCrochet = re.search('<salut[a-z\\n]*?>', text)
      mParenth = re.search('<salut(.|\\n)*?>', text)
      mProblematique = re.search('<salut[.\\n]*?>', text)
      
      print "mCrochet : \n" + mCrochet.group(0)
      print "mParenth : \n" + mParenth.group(0)
      print "mProblematique : " + str(mProblematique)

      Résultat de l'exécution

      mCrochet : 
      <salut
      plop
      plop
      >
      mParenth : 
      <salut
      plop
      plop
      >
      mProblematique : None
      
      • [^] # Re: Caractères spéciaux dans [ ]

        Posté par . Évalué à 2.

        Tu peux aussi t'en convaincre en soulignant que « [ ] » servent à spécifier une liste de caractères admissibles à une position donnée. Le point « . » signifiant « n'importe quel caractère », cela n'aurait pas de sens de l'insérer au sein d'une liste et au milieu d'autres caractères ordinaires qui, par définitons, sont déjà pris en compte par le « . » avec les autres.

  • # Autre manière de faire

    Posté par (page perso) . Évalué à 2.

    Attention, un détail, mais qui peut avoir son importance, comment souhaites-tu que soit parsé "<salut > truc>" ? Est-ce que tu veux que cela match "<salut >" (lazy), ou "<salut > truc>" (greedy) ? Je ne connais pas suffisamment python pour savoir comment se comporte les expressions régulières par défaut, mais c'est un détail qui a son importance ;)

    Comme je suppose que tu recherches du lazy. Dans ce cas, généralement, je procède ainsi :
    m = re.search('<salut [^>]*>', text);

    PS : je m'excuse d'avance pour tous les anglicismes, mais j'avoue que je n'ai pas de traductions propres en tête pour "parser", "matcher", "lazy" et "greedy" dans un tel contexte :)

    • [^] # Re: Autre manière de faire

      Posté par (page perso) . Évalué à 1.

      je n'ai pas de traductions propres en tête pour "parser", "matcher", "lazy" et "greedy" dans un tel contexte :)

      Dans l'ordre je crois : analyser, correspondre (il me semble avoir vu ça quelque part, mais je trouve ça bizarre), paresseux et glouton (en tous cas pour un algorithme glouton ça correspond bien). Mais bon, je n'ai pas l'impression que les deux premiers soient très courants.

    • [^] # Re: Autre manière de faire

      Posté par . Évalué à 1. Dernière modification le 18/10/13 à 22:18.

      Merci pour ta remarque, c'est intéressant cette différenciation lazy/greedy. Je ne m'étais jamais attardé là-dessus. C'est bien du lazy que je veux et on peut corriger ça en remplaçant * par *? :

      text = "plop\n<salut\nplop\n> plop>"
      
      #m = re.search('<salut(.|\\n)*>', text)
      m = re.search('<salut(.|\\n)*?>', text)

      Mais là où ça pose problème c'est la gestion du retour à la ligne, le '.' ne le matche pas et le \n ne semble pas vouloir être pris en compte dans la syntaxe avec les crochets. Je suis prêt à l'accepter comme ça, mais si quelqu'un pouvait me donner la raison j'aurai la satisfaction d'aller me coucher un peu moins idiot :-)

      Sinon j'ai mis le code en python parce que c'est plus facile à tester pour le lecteur du forum mais en fait je travaille sur du Java. Je n'avais pas fait gaffe que le comportement pouvait être différent.

      • [^] # Re: Autre manière de faire

        Posté par . Évalué à 1.

        C'est bien le point qui est littéral dans les [] et pas dans les (),
        en tout cas en python :

        text="abc"
        m = re.search('a[.]c', text)
        m
        m = re.search('a(.)c', text)
        m
        <_sre.SRE_Match object at 0x7f335dfdea08>

        • [^] # Re: Autre manière de faire

          Posté par . Évalué à 1.

          Merci pour cette idée de test. C'est ce qu'il me fallait pour comprendre le truc :-)

      • [^] # Re: Autre manière de faire

        Posté par (page perso) . Évalué à 1.

        le \n ne semble pas vouloir être pris en compte dans la syntaxe avec les crochets.

        Heu, si, peut-être pas en Java, mais en python et perl c'est interprété spécialement (à la différence près qu'en perl si on double le backslash [\\n] signifie backslash ou « n »).

        • [^] # Re: Autre manière de faire

          Posté par (page perso) . Évalué à 1.

          D'ailleurs, j'ai vérifié, et en python tu peux aller de un à trois backslashes devant le « n » et c'est toujours interprété (dans les [] ou dehors peu importe), et il en faut quatre pour obtenir \ ou n (la raison de la différence c'est qu'en python les expressions régulières utilisent les chaînes de caractères courantes, comme dans la plupart des langages).

      • [^] # Re: Autre manière de faire

        Posté par (page perso) . Évalué à 2.

        Concernant le retour à la ligne, en PHP (car oui, j'ai beaucoup utilisé les expressions régulières, mais en PHP ), tu peux préciser le comportement du point, et notamment s'il doit inclure ou non les sauts de ligne. Tu précises le comportement à l'aide de drapeaux à passer en paramètre de la fonction de recherche de correspondances.

        Peut-être existe-t-il un mécanisme similaire en java ;)

        • [^] # Re: Autre manière de faire

          Posté par . Évalué à 1.

          Effectivement. C'est le flag DOTALL
          Qu'est ce que mon code devient beau avec tous ça. Je vous montre ce que ça donne en utilisation réelle en Java :

          Pattern pattern = Pattern.compile("\\{\\{Deutsch Substantiv Übersicht.*?\\}\\}", Pattern.DOTALL);
          Matcher matcher = pattern.matcher(wikiPage);
          
          if( ! matcher.find() )
              throw new NoKasusAvailableException();
          String table = wikiPage.substring(matcher.start(), matcher.end());

          Où wikiPage contient la page vers un mot allemand (der Wagen) de de.wiktionary avec la syntaxe wikipedia. Et l'expression régulière doit récupérer le tableau dans lequel se trouvent les déclinaisons de ce mot.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.