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

Mon regex ne retourne que le premier et dernier match


Sujet :

Langage PHP

  1. #1
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut Mon regex ne retourne que le premier et dernier match
    Bonjour,

    Voici mon regex: ([ACEHLXPIS])+(B[1-2]|U[1-2]|V[1-2]|D1|G1)*
    L'entrée est celle-ci: AB1G1D1
    Au lieu de retourner: A-B1-G1-D1, il ne me retourne que le premier et dernier match, comme ceci: A-D1.

    J'ai certainement dû omettre quelque chose, pourriez-vous me donner un coup de main s'il vous plait?

    Merci,
    Babas007

  2. #2
    Modérateur
    Avatar de sabotage
    Homme Profil pro
    Inscrit en
    Juillet 2005
    Messages
    29 208
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juillet 2005
    Messages : 29 208
    Points : 44 155
    Points
    44 155
    Par défaut
    Comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ([ACEHLXPIS])([B1-2|U1-2|V1-2|D1|G1]+)

  3. #3
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Je ne savais pas qu'on pouvait écrire de cette forme: B1-2. Merci!
    Le résultat retourné est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        [2] => Array
            (
                [0] => B1G1D1
            )
    Hors je voudrai quelque chose comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        [2] => Array
            (
                [0] => B1
            )
        [3] => Array
            (
                [0] => G1
            )
        [4] => Array
            (
                [0] => D1
            )

  4. #4
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    A partir de l'index 1, les arrays sont des sous-groupes capturés. Si vous voulez de voir comment chaque composant dans l'alternation (|) soit capturer, il suffit de mettre chacun d'eux comme un sous-groupe lui-même.
    Code text : Sélectionner tout - Visualiser dans une fenêtre à part
    ([ACEHLXPIS])+((B[1-2])|(U[1-2])|(V[1-2])|(D1)|(G1))*

  5. #5
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Pas très élégant le résultat:
    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
     
    Array
    (
        [0] => Array
            (
                [0] => AB1G1D1
            )
     
        [1] => Array
            (
                [0] => A
            )
     
        [2] => Array
            (
                [0] => D1
            )
     
        [3] => Array
            (
                [0] => B1
            )
     
        [4] => Array
            (
                [0] => 
            )
     
        [5] => Array
            (
                [0] => 
            )
     
        [6] => Array
            (
                [0] => D1
            )
     
        [7] => Array
            (
                [0] => G1
            )
     
    )
    Et en plus y'a un doublon

  6. #6
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    Et en plus y'a un doublon
    Il y a un doublon parce que ça a une fonction bien déterminée dans le comptage de sous-groupe et c'est fondamental. Ce n'est pas en soi un problème. Mais si vous ne voulez absolument le pas voir vous pouvez utiliser la notion de sous-groupe non-retenu.
    Code text : Sélectionner tout - Visualiser dans une fenêtre à part
    ([ACEHLXPIS])+(?:(B[1-2])|(U[1-2])|(V[1-2])|(D1)|(G1))*
    Mais ça peut égarer certaines.

  7. #7
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Ahhh mieux! Par contre, dans mon cas, j'ai besoin de savoir s'il y a un doublon. Ce qui me génait dans le cas précédent, c'est que le résultat affiché un doublon alors qu'il y en avait pas

  8. #8
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    Merci pour le retour. Je ne le considère pas vraiment un doublon - mais il se peut que c'est un vocabulaire que j'ai mal compris. (Aussi je vais éditer mon message desus pour éliminer des typos génants.)

  9. #9
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    La seule chose que je reproche au regex là, c'est qu'il créer un duplicat alors qu'il y en a pas...

  10. #10
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    N'oublions pas que regex n'est qu'un outil du type fonctionnel, on est libre de faire tant qu'on veut autour regex si ça aide.

    Si on insiste, on peut faire comme ça tout en gardant un peu le but d'être élégant mesuré.
    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
    //$s='AB1G1D1';
    //$s='AB1G1D1U1B2';
    //$s='AB1G1D1U1B2B';
    $s='AB1G1D1U1B2B1';
     
    $phead='([ACEHLXPIS])+';
    $ptail='(B[1-2]|U[1-2]|V[1-2]|D1|G1)?';
    $p=$phead;
     
    /*
    $len-1
        parce que ([ACEHLXPIS])+ matche au moins un caractère
    strlen('B1')=2
        cas typique en supposant les alternatives sont la même longeur
        sinon prenons la longeur minimale, et à la limite prenons 1 tout simplement
    */
    $len=strlen($s);
    $max=(int)(($len-1)/strlen('B1'));
     
    for ($i=1; $i<=$max; $i++) {
        $p.=$ptail;
    }
     
    $pattern='/'.$p.'/';
     
    //pour faire le filtrage correctement
    $callback=function($item) use(& $callback) {
        if (is_array($item)) {
            return array_filter($item, $callback);
        }
        if (!empty($item)) {
            return true;
        }
    };
     
    preg_match_all($pattern, $s, $matches);
    $filtered=array_filter($matches, $callback);
     
    var_dump($filtered);
    Et voilà!

  11. #11
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Je suis entièrement d'accord avec toi. Mais je suis dans un cas assez particulier, le process suite à ce regex est générique, et de plus il est important de savoir s'il y a doublon ou non. C'est tellement dommage, tu es si proche de la solution...

    J'avais écrit ça: ([ACEHLXPIS]+|B[1-2]?|U[1-2]?|V[1-2]?|D1?|G1?)
    Mais ma chaine DOIT commencer par ACEHLXPIS, hors avec ce regex je peux commencer avec B...

    Petite boulette quand à la sortie, je veux que ça ressemble à ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    [1] => Array
            (
                [0] => A
                [1] => G1
                [2] => D1
                [3] => U1
                [4] => D1
            )
    Pour revenir à la source du problème, pourquoi le regex ne retourne que le dernier élément capturer?

  12. #12
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    Je n'ai pas encore digéré ton message; mais je regarde encore ce que j'ai posté et je vois j'ai manqué de mettre une ligne nécessaire, étant préoccupé d'écrire les commentaires qui suive, $p=$phead en initialisé $p. Je vais éditer le code desus peut-être ça a une portée sur ce que tu préoccupe dans le message ou peut-être pas?

  13. #13
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Quelles peuvent être les formes différentes de la chaine de départ ?
    Par ex. : les lettres (B, U, V, D, G) sont dans un ordre donné, ou peuvent être dans le désordre ?
    Dernière modification par Invité ; 06/11/2013 à 12h46.

  14. #14
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Dans le désordre, mais doit commencer par une ou plusieurs fois ACEHLXPIS

  15. #15
    Membre du Club
    Inscrit en
    Octobre 2010
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 205
    Points : 66
    Points
    66
    Par défaut
    Je reviens sur ce post, car je continue à rencontrer ce problème sur d'autres regex qu je construit, un exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    source = MDG0030 SEB0025
    Avec le regex suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    regex = (([a-zA-Z]{2,5})([01][0-9]|2[0123])([0-5][0-9])[ ]*){1,}
    Encore une fois, cela me retourne le dernier match... Je comprends pas du tout pourquoi, si je veux avoir tous les matchs je dois enlever le {1,} à la fin de la chaine. Le problème c'est qu'en faisant ça, le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    source.matches(regex) //returns false
    Quel est le regex qui me permettrait de retourne toutes les captures et que le code ci-dessus retoune true?

    Merci de votre aide

  16. #16
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 888
    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 888
    Points : 6 632
    Points
    6 632
    Par défaut
    En fait c'est simple: quand dans une pattern tu répètes un groupe capturant comme ici avec {1,} (ou * ou+) tu obtiendras toujours le dernier résultat. Car à chaque répétition la capture précédente est écrasée par la nouvelle.

    La solution la plus simple consiste à retirer ce dernier quantifier {1,} pour obtenir les résultats avec la method find():

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (([a-zA-Z]{2,5})([01][0-9]|2[0-3])([0-5][0-9])[ ]*)
    Mais elle a le désavantage de seulement trouver les motifs correspondants sans pour autant vérifier que l'ensemble de la chaîne est conforme.

    Visiblement tu utilises java. Tu ne peux pas à la fois vérifier la structure global de ta chaîne, et capturer tous les groupes que ce soit avec la méthode find() ou matches(), du fait que tu as un nombre indéterminé de sous chaînes.

    Une solution pourrait être de tester la structure de toute la chaîne par la méthode matches() avec cette pattern:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ^(?:[a-zA-Z]{2,5}(?:[01][0-9]|2[0-3])[0-5][0-9](?:[ ]+|$))+$
    Puis, dans un deuxième temps, d'effectuer un split de la chaîne sur les espaces (\s+)

    Une autre solution consisterai à utiliser la méthode find() avec \G pour vérifier que les résultats sont contigus (les uns à la suite des autres ou au début de la chaîne), puis de comparer l'index du dernier caractère de la dernière capture globale (end()) avec la taille de la chaîne de départ (pour vérifier qu'on est bien arrivé à la fin)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    \G([a-zA-Z]{2,5}(?:[01][0-9]|2[0-3])[0-5][0-9])(?:[ ]+|$)
    Example:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    String source = "MDG0030 SEB0025";
    List<String> result = new ArrayList<String>();
    Pattern p = Pattern.compile("\\G([A-Z]{2,5}(?:[01][0-9]|2[0-3])[0-5][0-9])(?:[ ]+|$)");
    Matcher m = p.matcher(source);
    while (m.find()) {
    	result.add(m.group(1));
    	System.out.println(source.length()+"\t"+m.end()+"\t"+m.group());
    }

Discussions similaires

  1. Réponses: 4
    Dernier message: 20/08/2011, 13h06
  2. mon while ne fonctionne que sur le premier select !
    Par gangrenn dans le forum Langage
    Réponses: 6
    Dernier message: 02/08/2010, 10h34
  3. Réponses: 2
    Dernier message: 14/06/2009, 17h01
  4. select qui retourne que le premier element
    Par sallemel dans le forum Hibernate
    Réponses: 6
    Dernier message: 12/12/2008, 17h40
  5. [RegEx] Mon regex ne fonctionne pas..la variable retourne Array
    Par joboy84 dans le forum Langage
    Réponses: 1
    Dernier message: 09/06/2008, 18h11

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