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 Java Discussion :

Expression régulière un peu tordue


Sujet :

Langage Java

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2013
    Messages
    61
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 61
    Points : 136
    Points
    136
    Par défaut Expression régulière un peu tordue
    Bonjour à tous,

    Supposons que j'ai du vieux code php à transformer pour éviter les "sql injections".

    AVANT:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $x->query("select aa from bb where bb='".$t['a']."'");
    APRES:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $x->query("select aa from bb where bb=?",array($t['a']));
    Ca je sais faire avec un truc du genre: newstr=str.replaceFirst("(\\-\\>query\\(.*)'\"\\.(.+)\\.\"'([^\\)]*)\\)", "$1?$3,array($2))");
    C'est déjà pas très lisible ...

    Maintenant ce que je ne sais pas faire :
    AVANT:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)");
    APRES:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $x->query("select aa from bb where (bb=?) and cc=? and (lasuite=2)",array($t['a'],$t['b']));
    Faisable ou pas avec une expression régulière (même dans un autre langage que java) ? car j'ai beau chercher je deviens
    L'idée en fait est qu'il y aura un nombre variable de "groupes" qu'il faut remplacer et déplacer (les $1, $2 ... ).

  2. #2
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Faisable avec une expression régulière: clairement non, sauf en Perl (qui permet l'exécution de code au sein même de la pattern et donc de stocker des captures répétées avant que la suivante n'écrase la précédente), en .net ou en Python avec le module pypi/regex (dans ces deux cas les captures répétées sont conservées au lieu de s'écraser les unes les autres comme avec les autres moteurs de regex.).
    Mais que les choses soient claires: attaquer quelque chose d'aussi complexe qu'un langage de programmation avec une regex est une entreprise plus qu'hasardeuse, car réaliser une telle expression nécessite d'y introduire la description d'une part importante de la syntaxe du langage cible (par exemple les commentaires, les chaînes, les parenthèses imbriquées) et de parcourir la totalité du script de bout en bout sans aucun blanc.
    Autrement dit, ton expression se vautrera à la moindre chiquenaude.

    À la limite, une expression régulière naïve pourra te faire gagner du temps en l'utilisant dans ton ide pour repérer les endroits que tu modifieras à la main.

    Autre option: utiliser un parser. C'est la méthode la plus robuste, mais ça ne sera pas forcément plus simple. PHP met à disposition son propre tokenizer via la fonction token_get_all().
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  3. #3
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2013
    Messages
    61
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 61
    Points : 136
    Points
    136
    Par défaut
    Merci de ta réponse, en effet je me doutais que ça ne serait pas simple.

    En fait j'envisage une autre option , un peu comme le tokenizer mais en mode simplet
    Disons que je n'ai pas besoin de traiter tous les cas qui "seraient possibles", mais tout simplement les cas concrets que j'ai observés.
    C'est du one shot, je ne vais pas construire un outil générique pour faire ce travail donc restons pragmatiques.

    J'ai déjà le fil conducteur en tête ça devrait le faire !

  4. #4
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    En PHP, en trichant un peu (en exploitant une fonction de callback pour construire la chaîne de remplacement avec une variable passée en référence), on peut faire ça:
    Code php : 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
    $pattern = <<<'EOD'
    ~
    # main pattern
    (?=[-"'</.)]) # first character discrimination
     
    (?: # contigous to a previous match
        \G (?!\A) # contigous, but not the start of the string
        (?: \. \g<ns>* (?= (?<cont>") (?<rsq>')? ) | \) (*ACCEPT))
      | # or the prefix
        ->query \g<ns>* \( \g<ns>* \K
      | # skip strings and comments
        \g<str> (*SKIP) (*F)
      |
        \g<c> (*SKIP) (*F)
    ) 
    (?<prestr> \g<dqstr> (?:(?<= =(?<lsq>')" | =" ) | \) (*ACCEPT)) )
    \g<ns>* \. \g<ns>*
    (?<expr>
        (?:(?!\.) \g<nb>)*+ 
        (?:\g<bracket> (?:(?!\.) \g<nb>)* )*+
        (?:\.(?-1))*? (?= \.\g<ns>*" | \) )
    )
      
    # subpatterns definitions 
    (?(DEFINE)
      # brackets
      (?<nb> [^][)(}{<'"] | \g<str> | \g<ns> | < )
      (?<roundB> \( \g<nb>*+ (?:\g<bracket> \g<nb>*)*+ \) )
      (?<squareB> \[ \g<nb>*+ (?:\g<bracket> \g<nb>*)*+ ] )
      (?<curlyB> { \g<nb>*+ (?:\g<bracket> \g<nb>*)*+ } )
      (?<bracket> \g<roundB> | \g<squareB> | \g<curlyB> )
      # strings
      (?<dqstr> " [^\\"]*+ (?s:\\.[^\\"]*)*+ " )
      (?<sqstr> ' [^\\']*+ (?s:\\.[^\\']*)*+ ' )
      (?<heredoc> <<<('?)([^\W\d]\w*)\g{-2}\R (?>.*\R)*? \g{-1} ;? $ )
      (?<str> \g<dqstr> | \g<sqstr> | \g<heredoc>) 
      # comments & whitespaces
      (?<c> \Q/*\E [^*]*+ (?:\*+(?!/)[^*]*)*+ (?: \Q*/\E | \z ) | //.*$ )
      (?<ns> \g<c> | \s+ ) # non significant
    )
    ~mx
    EOD;
     
    $test_string = <<<'EOD'
    $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)");
     
    $str = <<<'TOTO'
    $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)");
    TOTO;
     
    /* $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)"); */
     
    // $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)");
     
    $x->query("select aa from bb where (bb='".$t['a'] . $a ."') and cc=".$t['b']   );
     
    $x->query("select aa from bb where (bb='".$t['a'] . ($a->property/2*($b[$d[18].$e[1]]+($c/2))) ."') and cc=".$t['b']   );
     
    $x->query(//commentaire 
       "select aa from bb where (bb='".$t['a']
       . /*commentaire*/ "') and cc=".$t['b']." and (lasuite=2)");
     
    $x->query("select aa from bb where (bb='".$t['a']."') and cc=".$t['b']." and (lasuite=2)");
     
    $x->query("select aa from bb where (bb=?) and cc=? and (lasuite=2)",array($t['a'],$t['b']));
    EOD;
     
    $store = [];
     
    $result = preg_replace_callback($pattern, function ($m) use (&$store) {
        if ( !empty($m['expr']) ) {
            $store[] = trim($m['expr']);
            return substr($m['prestr'],
                !empty($m['cont']) + !empty($m['rsq']),
                -1 - !empty($m['lsq']) 
            ) . '?';
        } else {
            $values = implode(', ', $store);
            $store = [];    
            return (empty($m['prestr']) ? '"' : substr($m['prestr'], 1, -1))
                 . ', array(' . $values . '))';
        }
    }, $test_string);
     
    echo $result;

    Limitations: ça ne gère pas les variables directement introduites dans les chaînes à double quote, ni d'éventuels passages en html, et bien sûr c'est incapable de voir si la variable ne contient pas une partie du code SQL.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #5
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2013
    Messages
    61
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 61
    Points : 136
    Points
    136
    Par défaut
    Wow pas mal ton code, je vais essayer d'extraire un peu tous les cas que j'ai dans mon code et voir ce que ça donne !

    Par contre un truc que j'avais oublié et qu'on ne peut pas traiter c'est que souvent on a :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    [bout de code php]
    if (machin) $sql=" ...";
    else $sql="...";
    [bout de code php]
     
    $x->query($sql);

  6. #6
    Membre habitué
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Novembre 2013
    Messages
    61
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Novembre 2013
    Messages : 61
    Points : 136
    Points
    136
    Par défaut
    Damned en regardant tous les cas concrets, il y parfois un cas qui va causer des effets de bord , donc le traitement auto c'est rapé.

    Exemple: "select aa from bb where id ".$boutdesql." suite du sql" , si on remplace $boutdesql par ? ça va planter ou avoir des effets imprévisibles.

    J'y ai cru ... mais il va falloir mettre les mains dans le cambouis

  7. #7
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Citation Envoyé par remotesolo Voir le message
    le traitement auto c'est rapé.
    [En même temps], c'était un peu couru d'avance.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

Discussions similaires

  1. Un peu d'expression régulière..
    Par johnaliashead dans le forum C#
    Réponses: 2
    Dernier message: 31/01/2013, 17h57
  2. Un peu d'aide sur une expression régulière particulier
    Par ruana dans le forum Général Python
    Réponses: 2
    Dernier message: 03/06/2007, 19h04
  3. [RegEx] Une expression régulière avec un peu de tout
    Par JackBeauregard dans le forum Langage
    Réponses: 2
    Dernier message: 17/04/2007, 09h50
  4. Réponses: 5
    Dernier message: 11/06/2002, 15h21

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