Forum Programmation.c regex.h Lazy Mode

Posté par  .
Étiquettes :
0
24
mar.
2006
Bonjour,
J'essaye d'utiliser les regex de regex.h en lazy mode i.e. :
si j'ai une chaine : "tititototatatoto" et que ma regex est "(.*?)toto",
je voudrais matcher juste titi et pas tititototata en back ref.

Avec ce petit programme perl ca marche, ca affiche titi:
perl -e '$_="tititototatatoto"; m/(.*?)toto/; print $1,"\n";'

avec ce programme C ca marche pas :
#include <regex.h>
int main(){
regex_t preg; regmatch_t pmatch[2];
regcomp (&preg, "(.*?)toto" , REG_EXTENDED|REG_ICASE);
regexec (&preg, "tititototatatoto", 2, pmatch,0);
size_t len = pmatch[1].rm_eo-pmatch[1].rm_so;
char * match = malloc(len+1);
memcpy(match,"tititototatatoto",len);
match[len] = 0;
printf("%s\n",match);
}
affiche tititototata...

Apparemment dans la doc que j'ai pu trouvé elle devrait prendre en compte le lazy mode...
Quelqu'un a une idée ?? (glibc2.0 Fedora 4)
Merci d'avance
  • # Une idee comme ça...

    Posté par  . Évalué à -1.

    int main(){

    Non: int main (void) ou int main(int argc, char *argv[]) (ou une formulation équivalente pour la seconde). Tout autre prototype est une extension; et le int main() seul est un prototype incomplet.
    regcomp (&preg, "(.*?)toto" , REG_EXTENDED|REG_ICASE);

    regcomp() renvoie un code de sortie, il faut le vérifier. POSIX.2 [1] dit:
    Upon successful completion, the regcomp() function shall return 0. Otherwise, it shall return an integer value indicating an error as described in <regex.h>, and the content of preg is undefined. If a code is returned, the interpretation shall be as given in <regex.h>.

    Note bien le undefined. En jargon C, ça veut vraiment dire indéfini, i.e. si tu accèdes au contenu de preg après une erreur de regcomp, tout peut se produire, du comportement que tu pensais obtenir, jusqu'au plantage, au crash disque, ou à des démons qui sortent de ton nez.

    Idem pour regexec():
    Upon successful completion, the regexec() function shall return 0. Otherwise, it shall return REG_NOMATCH to indicate no match.
    (enfin, tu n'es pas obligé pour regexec(), ça dépend du traitement que tu fais après. Pour un debug, je te conseille de vérifier le résultat).

    char * match = malloc(len+1);

    Il faut vérifier le résultat de *alloc(). En cas d'échec de cete fonction, si tu ne fais pas cette vérification, tu déréférenceras un pointeur nul, d'où un comportement indéfini, soit la ligne suivante (memcpy() avec un len non nul), soit celle d'après (si len est nul).
    De plus, il manque le #include <stdlib.h>, d'où encore un comportement indéfini: sans prototype de malloc visible, le compilateur est obligé de supposer que la fonction renvoie un int. Comme tu assignes cette valeur à un pointeur, cela viole une contrainte (6.5.16.1 du n1124), d'où un comportement indéfini. Si tu rajoutes un cast, le comportement n'est plus indéfini (les contraintes sont vérifiées), mais dépendant de l'implémentation (conversion d'entier en pointeur, 6.3.2.3p5, et 6 pour la conversion inverse). La bonne solution est donc de placer le #include qui va bien.

    printf("%s\n",match);
    }
    Un return 0; (ou return EXIT_SUCCES; avec l'include qui va bien) serait mieux, vu que main() renvoie un int. C99 autorise de ne pas le faire, mais c'est toujours mieux de finir une fonction ne renvoyant pas void par un return XX;.

    [1] http://www.opengroup.org/onlinepubs/009695399/toc.htm Il faut s'inscrire, mais c'est gratuit et téléchargeable par la suite, ou consultable en ligne.
    • [^] # Re: Une idee comme ça...

      Posté par  . Évalué à 2.

      Bon c'est bien gentil tout ca mais le but c'est pas d'avoir 20/20 a mon exo et que le prof soit content de moi mais de faire rapidement un petit exemple qui compile pour que les gens m'aide à resoudre mon probleme.... Merci de ne pas debattre de savoir si il faut mettre (void) plutot que () dans int main() ou autre par la suite, CA NE M'INTERESSE PAS.
      • [^] # Re: Une idee comme ça...

        Posté par  . Évalué à 0.

        Tu poses une question, j'essaye d'y répondre, avec mes connaissances. J'ai soulevé deux comportements indéfinis dans ton programme, ce qui signifie qu'étudier tout comportement de ce programme tel quel est inutile. Il est indéfini au niveau du C ISO (cf. malloc) et au niveau de POSIX.2 (cf. regcomp), donc tout peut arriver.

        J'ai aussi remarqué (et c'est lié à ce qui précède) que tu ne testais pas les codes de retour des fonctions que tu appelles, ce qui t'empêche de savoir à partir d'où il s'écarte du comportement que tu attends. Si tu le faisais, tu pourrais cerner plus précisément le problème, et le résoudre assez vite (à mon avis). Etait-ce inutile de te le dire ? Avec le code que tu as posté, tu ne sais pas si regcomp plante, si c'est regexec, malloc, memcpy ou printf...

        Pour le type de main(), désolé si ça t'énerve, mais il y a des gens dans d'autres fora ou newsgroups (pas moi, note) qui ne prennent même pas la peine de répondre à ceux qui ne savent pas comment l'écrire. J'ai pris la peine de te dire que ton code comportait un souci à ce niveau (plus précisément, et sauf erreur de ma part, utilisation d'une deprecated feature du C ISO, datant de l'époque K&R), et je t'ai donné les deux prototypes portables. J'aurais pu ne pas le faire. Libre à toi de ne pas prendre en compte mon message sur ce point.

        Tiens, en passant, je n'avais pas fait attention que printf() et memcpy() n'avaient pas leur include non plus (respectivement stdio.h et stdlib.h). Pense à utiliser un niveau de warning suffisant pour ton compilateur (-O2 -Wall -Wextra pour gcc 4, par exemple (de tête)).
        • [^] # Re: Une idee comme ça...

          Posté par  . Évalué à 2.

          Moi, je dis que tu as bien raison...

          Il aurait du poster tous le code de tous son projet, avec les includes et tout et tout.
          Parce que bon, c'est pas parce que tu ne réponds pas à sa question que tu ne peux pas le sauver de la perdition.
          • [^] # Re: Une idee comme ça...

            Posté par  . Évalué à 1.

            Je ne demande pas le code complet de son projet, juste un code compilable.
            Et je ne prétends pas le sauver de la perdition, je note juste un certain nombre de problèmes (plus ou moins importants) dans son code.

            Et non, je n'ai pas la réponse à sa question, je ne sais pas quel est l'endroit exact où son code s'écarte du comportement qu'il attend (à part peut-être ci-dessous). Mais j'ai repéré des endroits où le comportement est indéfini, i.e. tout et n'importe quoi peut se produire, y compris et surtout quelque chose qu'il ne veut pas (typiquement, un comportement indéfini peut causer une erreur de compilation, ou une erreur de segmentation à l'exécution si ça compile, ou un programme qui ne plante pas mais a un comportement incorrect), et je lui ai fait remarquer qu'en vérifiant les codes de retour des fonctions qu'il appelle, il pourrait cerner le problème plus facilement...

            Après, je n'ai pas de compilateur C sous la main pour l'instant, je ne peux donc tester son code. Je n'ai pas utilisé regex.h, donc je ne peux voir s'il s'agit d'une erreur (évidente ou non) d'utilisation de ces fonctions.

            A part peut-être, dans la doc POSIX (que j'ai donnée dans mon premier mail), je viens de trouver ça:
            When matching a basic or extended regular expression, any given parenthesized subexpression of pattern might participate in the match of several different substrings of string, or it might not match any substring even though the pattern as a whole did match. The following rules shall be used to determine which substrings to report in pmatch when matching regular expressions:

            1. If subexpression i in a regular expression is not contained within another subexpression, and it participated in the match several times, then the byte offsets in pmatch[ i] shall delimit the last such match.

            Donc le résultat qu'il obtient vient peut-être de là...
  • # PCRE

    Posté par  . Évalué à 2.

    Bon pour conclure la glibc n'implemente pas, pour l'instant, les comportements non-greedy (ou lazy quoi) du type *? +? ou encore ?? ce qui est tres bizarres car quasi vitale en regex mais il y a une solution :
    Pour cela, il faut utiliser la lib PCRE. (pcre_exec, pcre_compile ...)

    Bon du coup je poste pas de code je risque de pas etre fully compatible ANSI C ISO 99... Des fois que ca jetterai le trouble chez quelques personnes... ANSI rigides...
    • [^] # Re: PCRE

      Posté par  . Évalué à 2.

      Allez, s'il te plait... poste le code !!!

      Mais n'oublie pas la license au début... sinon tu ne sera pas "GNU compliant"
    • [^] # Re: PCRE

      Posté par  . Évalué à 1.

      Bon du coup je poste pas de code je risque de pas etre fully compatible ANSI C ISO 99... Des fois que ca jetterai le trouble chez quelques personnes... ANSI rigides...

      :)
      Je n'ai rien contre les extensions au C (POSIX, GNU... ou tout ce qui tourne sur ta machine), par contre j'en ai contre les erreurs de programmation (en C, un comportement indéfini est une erreur). Quand un programme peut tenter d'accéder à une zone mémoire qui ne lui appartient pas, je ne vois pas en quoi c'est être rigide de dire qu'il y a un problème potentiel.
      Peut-être savais-tu que c'était une erreur dans ton code d'exemple, dans ce cas tu pouvais l'écrire, même en commentaire dans le code.
      De même pour les include, ça ne t'aurait pas coûté pas grand chose d'ajouter deux lignes à ton programme.
      Pour d'autres points (main, ou return 0, par ex.), je voulais juste montrer une autre façon de faire (le main() sans argument est quand même deprecated depuis un moment...). Juste une question de style, sans plus.

      Voilà. Maintenant, je suis content pour toi si tu as trouvé une solution à ton problème, qu'elle soit C ISO ou non d'aileurs, ou même dans un autre langage. L'important est que ta machine fasse çe que tu veux qu'elle fasse...

      (et, cf. mon autre post, le problème ne viendrait peut-être pas directement de la glibc, mais des spécifications POSIX, que la glibc semble respecter pour le coup)

Suivre le flux des commentaires

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