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

Langage Perl Discussion :

Pourquoi faut il un {;} dans un regex pour qu'il fonctionne ? [perl6]


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut Pourquoi faut il un {;} dans un regex pour qu'il fonctionne ?
    Bonjour,

    Je cherche une explication pour un fonctionnement que je ne comprends pas.

    1 - le code suivant ne fonctionne pas comme je le désire :

    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
    #!/opt/rakudo-star-2016.10/bin/perl6
    use v6;
    #use Grammar::Tracer;
    #use Grammar::Debugger;
     
    grammar DECODE {
     
        rule  TOPDECODE     { [<main>]* <textfin> }
          rule  main     { <text> <decode> }
            rule  decode {:i <decodeinstr> <paraIn> <val> <whenthen>+ [<comma> <else>] <paraOut>
                          |  <decodeinstr> <paraIn> <val> <whenthen>+ <paraOut> }
              regex decodeinstr {:i 'decode'\s* }
              regex val    {:s <decode>
                               |<expr> }
              regex  whenthen {:i <comma> <when> <comma> <then> }
                regex when    {:s <decode>
                                 | <expr> }
                regex then    {:s <decode>
                                 |<expr> }
                regex else    {:s <decode>
                                 |<expr> }
            regex text    {:s .+? }
          regex textfin {:s .+ }
          regex comma   {\s*','\s* }
          regex paraIn  {\s*'('\s*}
          regex paraOut {\s*')'\s*}
          token ws { <!ww> }
          regex expr  {:s <mot1>*
                          | [<mot1><paraIn><mot>*<paraOut>]*
                          | [<paraIn><mot>*<paraOut>]*
                      }
          rule mot  { <-[()]>+?  }
          rule mot1  { <-[(),]>+?  }
    }
     
     
    my $sqlStmt="select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) )  from dual ";
     
        say DECODE.parse($sqlStmt, rule => 'TOPDECODE');
    le résultat donne :
    「select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) ) from dual 」
    textfin => 「select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) ) from dual 」

    La fonction decode n'est pas reconnu.

    2 - Le code suivant, lui, reconnait bien la fonction decode. La seule difference concerne la ligne 28:

    code 1 ligne 28 -> regex expr {:s <mot1>*
    code 2 ligne 28 -> regex expr {:s {;}<mot1>*

    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
    #!/opt/rakudo-star-2016.10/bin/perl6
    use v6;
    #use Grammar::Tracer;
    #use Grammar::Debugger;
     
    grammar DECODE {
     
        rule  TOPDECODE     { [<main>]* <textfin> }
          rule  main     { <text> <decode> }
            rule  decode {:i <decodeinstr> <paraIn> <val> <whenthen>+ [<comma> <else>] <paraOut>
                          |  <decodeinstr> <paraIn> <val> <whenthen>+ <paraOut> }
              regex decodeinstr {:i 'decode'\s* }
              regex val    {:s <decode>
                               |<expr> }
              regex  whenthen {:i <comma> <when> <comma> <then> }
                regex when    {:s <decode>
                                 | <expr> }
                regex then    {:s <decode>
                                 |<expr> }
                regex else    {:s <decode>
                                 |<expr> }
            regex text    {:s .+? }
          regex textfin {:s .+ }
          regex comma   {\s*','\s* }
          regex paraIn  {\s*'('\s*}
          regex paraOut {\s*')'\s*}
          token ws { <!ww> }
          regex expr  {:s {;}<mot1>*
                          | [<mot1><paraIn><mot>*<paraOut>]*
                          | [<paraIn><mot>*<paraOut>]*
                      }
          rule mot  { <-[()]>+?  }
          rule mot1  { <-[(),]>+?  }
    }
     
     
    my $sqlStmt="select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) )  from dual ";
     
        #say DECODE.parse($fic, rule => 'TOPDECODE',actions => Decode).made;
        say DECODE.parse($sqlStmt, rule => 'TOPDECODE');
    Résultat:
    「select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) ) from dual 」
    main => 「select decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) ) 」
    text => 「select 」
    decode => 「decode(ti_res_pat_abs,'O',0,nvl(dual.dummy,0) ) 」
    decodeinstr => 「decode」
    paraIn => 「(」
    val => 「ti_res_pat_abs」
    expr => 「ti_res_pat_abs」
    mot1 => 「ti_res_pat_abs」
    whenthen => 「,'O',0」
    comma => 「,」
    when => 「'O'」
    expr => 「'O'」
    mot1 => 「'」
    mot1 => 「O」
    mot1 => 「'」
    comma => 「,」
    then => 「0」
    expr => 「0」
    mot1 => 「0」
    comma => 「,」
    else => 「nvl(dual.dummy,0) 」
    expr => 「nvl(dual.dummy,0) 」
    mot1 => 「nvl」
    paraIn => 「(」
    mot => 「dual」
    mot => 「.」
    mot => 「dummy」
    mot => 「,」
    mot => 「0」
    paraOut => 「) 」
    paraOut => 「) 」
    textfin => 「from dual 」

    La fonction decode est bien reconnu.

    Je ne comprends pas comment expliquer ce comportement. Pour moi, le premier code devrait fonctionner de manière identique au second... Ai-je raison ?
    Si vous avez une explication, je suis preneur.

    Merci beaucoup pour votre aide.
    Bien cordialement,
    Jean-Pierre

  2. #2
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Bon, je partage l'explication que j'ai obtenu sur le chat IRC de Raduko:

    "with {;} (even though {} should also work) you can force the declarative prefix to end earlier than it otherwise would"

    Il est donc normal que {} change le comportement du parsing. En continuant mes tests, je me suis aperçu que {} n'avait pas toujours une infuence positive sur mon resultat ... Cela veut certainement dire que ma grammaire n'est pas forcément la bonne...

    Voilà,
    Bien cordialement,

  3. #3
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Oups, j'ai fait des tests ce weekend et voulais te répondre après quelques tests complémentaires, mais j'ai oublié ensuite, désolé. Mais, de toute façon, je n'avais pas de réponse bien précise à apporter, si ce n'est que je craignais que ça ne fasse marcher de façon bancale quelque chose qui ne devrait pas vraiment marcher, et donc que ça ne cache en fait un bug.

    Franchement, je trouve ta grammaire bien compliquée, je suis sûr qu'il doit y avoir moyen de faire plus simple et plus limpide, mais je n'ai pas de conseil précis car je ne comprends pas les raisons de toutes les complexités introduites.

  4. #4
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Aucun souci pour le délai de réponse, je trouve cela déja miraculeux que quelqu'un me réponde sur un tel sujet.

    1 - Je suis entièrement d'accord sur la complexité de ma grammaire. Je l'ai construite par essai/erreur. Son avantage est qu'elle fonctionne ... sauf que j'ai quelques soucis avec certains cas particuliers...

    2 - Les specs se résume assez bien en disant que l'objectif est de traduire la fonction "decode()" décrite par https://docs.oracle.com/cd/B19306_01...nctions040.htm
    en fonction case décrite par http://docs.oracle.com/cd/B19306_01/...essions004.htm ou par https://www.postgresql.org/docs/9.6/static/functions-conditional.html

    Tout en précisant que
    - l'instruction "decode"peut se retrouver 0 ou n fois dans un texte quelqconque.
    - l'instruction "decode" se situe n''importe où dans ce texte, à l'exception du premier mot. ( Le texte ne peut pas commencer par un decode, mais il peut finir par un "decode")
    - 2 "decode" ne devrait pas se suivre. Il seront séparés au minimun par une virgule ou par n'importe quel texte.
    - Chaque paramètre du decode peut être un autre decode.
    - Chaque parametre du decode peut être une autre fonction( ex nvl(toto,titi) , une expression (ex: (2*(toto/4)), une valeur ( ex: 'toto' ou table1.col1) .

    Il faut que l'AST obtenu puisse être modifié de façon à obtenir un nouvel AST representant l'instruction case...

    3 - J'ai l'impression que je viens de résoudre mes problèmes en remplaçant :
    rule mot { <-[()]>+? }
    rule mot1 { <-[(),]>+? }
    par
    regex mot { <-[()]>+? }
    regex mot1 { <-[(),]>+? }
    Je peux même supprimer le {;} ... le bonheur ...

    Ci-dessous, un exemple de code traduisant les 2 ordres :
    ( codés en dur dans ce code)
    1 - "SELECT decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE')) from toto " ;
    2 - "SELECT decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE')) from toto order by decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE'))" ;

    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
    110
    111
    112
    6
    #!/opt/rakudo-star-2016.10/bin/perl6
    use v6;
     
    grammar DECODE {
     
        rule  TOPDECODE     { [<main>]* [<textfin>]? }
          rule  main     { <text> <decode> }
            rule  decode {:i <decodeinstr> <paraIn> <val> <whenthen>+ [<comma> <else>]? <paraOut> }
              regex decodeinstr {:i 'decode'\s* }
              regex val    {:s <decode>
                               |<expr> }
              regex  whenthen {:i <comma> <when> <comma> <then> }
                regex when    {:s <decode>
                                 | <expr> }
                regex then    {:s <decode>
                                 |<expr> }
                regex else    {:s <decode>
                                 |<expr> }
            regex text    {:s .+? }
          regex textfin {:s .+ }
          regex comma   {\s*','\s* }
          regex paraIn  {\s*'('\s*}
          regex paraOut {\s*')'\s*}
          token ws { <!ww> }
          regex expr  {:s <mot1>*
                          | [<mot1><paraIn><mot>*<paraOut>]*
                          | [<paraIn><mot>*<paraOut>]*
                      }
          regex mot  { <-[()]>+?  }
          regex mot1  { <-[(),]>+?  }
    }
     
     
    class Decode {
     
     method TOPDECODE ($TOPDECODE) {
       my $result ~= $_.made for $TOPDECODE<main>;
       if ($TOPDECODE<textfin>) {
          $result ~= $TOPDECODE<textfin>;
       }
       $TOPDECODE.make($result);
     }
     
     method main ($main) {
       $main.make($main<text> ~ $main<decode>.made) ;
     }
     
     method decode ($decode) {
       my $resuD ~= ' CASE ' ~ $decode<val>.made ;
          $resuD ~=  $_.made for $decode<whenthen> ;
       if $decode<else> {
         $resuD ~=  $decode<else>.made ~ ' END ' ;
       }
       else {
         $resuD ~=  ' END ' ;
       }
       $decode.make($resuD) ;
     }
     
     method val ($val) {
       my $resuVal;
       if $val<decode> {
         $resuVal = $val<decode>.made ;}
       else {
         $resuVal = $val<expr> ;
       }
       $val.make($resuVal);
     }
     
     method whenthen ($whenthen) {
       my $resuWT ~= " when " ~ $whenthen<when>.made ~ " then " ~ $whenthen<then>.made ;
       $whenthen.make($resuWT) ;
     }
     
     method then ($then) {
       my $resuThen;
       if $then<decode> {
         $resuThen = $then<decode>.made ;}
       else {
         $resuThen = $then<expr> ;
       }
       $then.make($resuThen);
     }
     
     method when ($when) {
       my $resuWhen;
       if $when<decode> {
         $resuWhen = $when<decode>.made ;}
       else {
         $resuWhen = $when<expr> ;
       }
       $when.make($resuWhen);
     }
     
     method else ($else) {
       my $resuElse;
       if $else<decode> {
         $resuElse = $else<decode>.made ;}
       else {
         $resuElse = $else<expr> ;
       }
       $else.make(' else ' ~ $resuElse);
     }
     
    }
     
     
     my $cbl = "SELECT decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE')) from toto " ;
    say  DECODE.parse($cbl, rule => 'TOPDECODE',actions => Decode).made;
     $cbl = "SELECT decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE')) from toto order by decode(val,exp1,exp2,exp3,exp4,nvl(exp5,'VIDE'))" ;
    say  DECODE.parse($cbl, rule => 'TOPDECODE',actions => Decode).made;
    Cela a l'air de fonctionner, pas forcément hyper-rapide. Bien sur, je suis preneur d'une simplification de la grammaire ou d'amélioration du code dans la classe.

    Merci encore pour l'aide.

    Bien cordialement.

  5. #5
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Un petit complément :

    le mieux est d'utiliser :
    regex mot { <-[()]>+ }
    regex mot1 { <-[(),]>+ }
    au lieu de
    regex mot { <-[()]>+? }
    regex mot1 { <-[(),]>+? }

    Fonctionner en mode frugal ne sert à rien et le mode gourmand doit être plus performant ....

    Voilà,
    Encore merci.
    Bien cordialement,

  6. #6
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Octobre 2016
    Messages
    39
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2016
    Messages : 39
    Par défaut
    Après de nouveau tests, je m'oriente vers l'utilisation de l'adverbe :ratchet pour le regex expr. Cela me permet d'avoir de meilleure performance et la grammaire semble fonctionner comme je le souhaite. Cela donne :

    regex expr {:s:r <mot1>*
    | [<mot1><paraIn><mot>*<paraOut>]*
    | [<paraIn><mot>*<paraOut>]*
    }
    regex mot {:r <-[()]>+ }
    regex mot1 {:r <-[(),]>+ }


    Du coup, je demande qu'elle est la différence entre une rule ou un token et un regex avec l'adverbe :ratchet ?

    Merci beaucoup pour votre aide.
    Bien cordialement,

  7. #7
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jeepc Voir le message
    Un petit complément :

    le mieux est d'utiliser :
    regex mot { <-[()]>+ }
    regex mot1 { <-[(),]>+ }
    au lieu de
    regex mot { <-[()]>+? }
    regex mot1 { <-[(),]>+? }

    Fonctionner en mode frugal ne sert à rien et le mode gourmand doit être plus performant ....
    Avec une classe de caractères aussi symétrique, il doit être assez difficile de trouver un texte ayant un sens dans ton contexte pour lequel le mode gourmand ou frugal fait une différence.

    Toutefois, je ne suis pas convaincu a priori que le mode gourmand soit plus performant que le mode frugal (mais c'est bien sûr possible). As-tu fait des benchmarks étayant cette hypothèse?

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

Discussions similaires

  1. [RegEx] regex pour trouver une fonction php5.2 dans fichier
    Par cedrick21 dans le forum Langage
    Réponses: 1
    Dernier message: 18/03/2016, 23h22
  2. Regex pour recherche dans une chaine
    Par ttornado dans le forum Framework .NET
    Réponses: 3
    Dernier message: 27/02/2013, 10h13
  3. [RegEx] caractère pour remplacer tous les caractères dans une regex
    Par sp2308 dans le forum Langage
    Réponses: 6
    Dernier message: 09/02/2008, 01h06
  4. Regex pour enlever les chemin dans un binaire
    Par rgesnot dans le forum Langage
    Réponses: 1
    Dernier message: 19/09/2007, 16h03
  5. Réponses: 5
    Dernier message: 10/07/2006, 15h02

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