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

Collection et Stream Java Discussion :

Problème d'expression régulière


Sujet :

Collection et Stream Java

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut Problème d'expression régulière
    Bonjour,

    Je désire écrire une regexp qui me permet de vérifier si un string se terminant par un "." matche un pattern qui respecterait une règle du genre:

    org.projet.A. matché
    org.projet.A.xxx. matché
    org.projet.A.xxx.B. non matché
    org.projet.A.xxx.C. non matché
    org.projet.A.xxx.B.yyy. non matché
    org.projet.A.xxx.C.yyy. non matché
    org.projet.A.xxx.B.yyy.A. matché
    org.projet.A.xxx.B.yyy.A.zzz. matché
    org.projet.A.xxx.B.yyy.A.zzz.B. non matché
    org.projet.A.xxx.B.yyy.A.zzz.C. non matché
    org.projet.A.xxx.B.yyy.A.zzz.B.www. non matché
    org.projet.A.xxx.B.yyy.A.zzz.C.www. non matché

    bref, le pattern doit matcher, si après la dernière occurrence de A (en mode greedy) on ne trouve aucune occurrence de B ou C.

    J'ai essayé plusieurs patterns mais sans succès pour représenter ceci. Parmis mes essais les plus proches :

    .+\.A\.(.+\.)*(?<!(B|C)\.)

    En effet, avec :

    org.projet.A.xxx.B.yyy.A.zzz.C.www.

    Je me retrouve avec ce résultat (qui match alors qu'il ne devrait pas :

    group(0) = "org.projet.A.xxx.B.yyy.A.zzz.C.www."
    group(1) = "zzz.C.www."
    group(2) = "null"

    En effet vu que je fonctionne en mode greedy, c'est bien la dernière occurrence de A qui est détectée, mais (?<!(B|C)\.) ne me permet apparemment pas trouver B ou C dans la group 1 (je ne détecte que si le groupe se finit par B. ou C.)

    Aidez moi svp j'ai passé des heures à faire des essais dans tous les sens mais sans succès...

    Ah oui je désire faire ceci en une seule seule regexp... (oui sinon ce serait simple, de faire un match de \.(B|C)\. sur \1, mais je ne peux pas le faire)

    Merci d'avance !

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Et cette regex, c'est bon ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String regex = "A(\\.[^\\.]+)?\\.$";
    Elle matche tous les cas que tu souhaites, si je me réfère à ton exemple.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Peux-tu expliquer ta regexp stp ?

    S'il y a .B. ou .C. après .A. (et ce où que ce soit) alors elle ne doit PAS matcher.

    merci :-)

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Pour l'explication, elle recherche la présence de A suivi d'un point. Ce A. peut éventuellement être suivi par n'importe quoi qui se termine par un point (et qui n'en contient pas plus).

    Avec les exemples, j'avais compris qu'il fallait quelque chose entre A et B ; que le xxx, yyy, etc. devaient absolument valoir quelque chose.

    Donc oui, ma regex matche :
    org.projet.A.
    org.projet.A.xxx.
    org.projet.A.xxx.B.yyy.A.
    org.projet.A.xxx.B.yyy.A.zzz.

    Elle ne matche pas :
    org.projet.A.xxx.B.
    org.projet.A.xxx.C.
    org.projet.A.xxx.B.yyy.
    org.projet.A.xxx.C.yyy.
    org.projet.A.xxx.B.yyy.A.zzz.B.
    org.projet.A.xxx.B.yyy.A.zzz.C.
    org.projet.A.xxx.B.yyy.A.zzz.B.www.
    org.projet.A.xxx.B.yyy.A.zzz.C.www.

    Ici, on a tous les exemples que tu donnes. C'est là dessus que je me suis basé.

    Parmi les exemple que tu n'as pas donnés, elle matchera :
    org.projet.A.B.
    org.projet.A.C.

    Et ne matchera pas :
    org.projet.B.
    org.projet.C.
    org.projet.D.



    Pourrais-tu mettre un test en profondeur (cas spéciaux inclus) s'il te plaît ? Je tenterai de te la construire.


    Je viens de trouver cette regex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String regex = "(^|\\.)A(\\.[^(?:A)(?:B)(?:C)(?:[^\\.]+)])*\\.$";
    Elle signifie, trouve un A qui soit suivi par un point, puis par un nombre quelconque de champ qui ne comportent pas de lettre et sont différents de B ou C. Dans tous les cas, il faut un point en dernier caractère. La deuxième présence de A force le moteur de regex à prendre le dernier A visible. Le premier point est un délimiteur, interdisant de matcher A comme faisant partie d'un mot complet (FA, par exemple).

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par mpawlak Voir le message
    S'il y a .B. ou .C. après .A. (et ce où que ce soit) alors elle ne doit PAS matcher.
    En me basant là-dessus, je te propose :

    Pour commencer, une regex qui matche les chaînes de caractère ne contenant pas ".B." (ni ne commençant par "B." ni ne finissant par ".B" d'ailleurs)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String regex = "([^B]|(B[^\\.]+)|([^\\.]+B))*";
    Explication : si le caractère 'B' est présent dans la chaîne alors il doit être soit suivi soit précédé d'au moins 1 caractère différent de '.'

    A partir de cette première expression, une regex qui matche les chaînes telles que si la sous-chaîne ".B." ou ".C." est présente alors elle est suivie de ".A."
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    String regex = "([^BC]|((B|C)[^\\.]+)|([^\\.]+(B|C)))*" +
                   "(\\.(B|C)\\..*\\.A\\.)*" +
                   "([^BC]|((B|C)[^\\.]+)|([^\\.]+(B|C)))*";
    Explication :
    - une chaîne de caractère ne contenant ni ".B." ni ".C."
    - de 0 à n fois ".B.xxxxx.A." ou ".C.xxxxx.A." (les xxxx pouvant contenir du A, du B ou du C, mais on s'en fiche puisqu'à la fin il y a bien un ".A.")
    - une chaîne de caractère ne contenant ni ".B." ni ".C."
    ce qui assure que si la sous-chaîne ".B." ou ".C." est présente, alors elle a été matchée par l'expression centrale et donc elle est bien suivie de ".A."


    A vérifier (je peux me tromper), à adapter éventuellement (en particulier pour traiter les cas où le premier package est B ou C, ou le dernier package est A), à optimiser probablement... mais je pense que ça devrait marcher

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Merci pour vos réponses mais je crois que je dois préciser un peu :

    1) A, B ou C sont une substring d'un nom de package (des chaines de caractère donc et non pas un caractère unique. Nommons les donc AAA, BBB, CCC pour que ceci soit plus clair.

    On peut retrouver celles-ci n'importe-où dans un nom de package (p.ex. "util" dans java.util. ou java.util.regexp.

    2) tous mes noms de package se terminent par un "." (ex "java.util.regexp.") je ne peux changer ceci

    3) la lib de regexp que j'utilise est java.util.regexp (je précise vu que les comportements ne sont pas identiques selon les implémentations je crois)

    4) En gros ce que je veux faire "en français", est que si j'ai un nom de package java contenant .AAA. je veux que mon pattern matche, *sauf* si le dernier .AAA. est suivi par un .BBB. ou un .CCC. et ce où que ce soit après le dernier .AAA.

    5) Par conséquent les chaines suivantes doivent matcher

    xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.

    mais pas les suivantes :

    xxxxxx.AAA.BBB. (le .BBB. après le .AAA. empêche le match)
    xxxxxx.AAA.xxxxxx.BBB.
    xxxxxx.AAA.BBB.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.
    xxxxxx.AAA.CCC. (le .CCC. après le .AAA. empêche le match)
    xxxxxx.AAA.xxxxxx.CCC.
    xxxxxx.AAA.CCC.xxxxxx.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.BBB.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.BBB.xxxxxx
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.CCC.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.CCC.xxxxxx.

    6) mon but est de trouver une regexp unique pour y arriver. Je ne peux pas toucher au code.

    Est-ce plus clair ? :-)

    Vraiment merci de votre aide car je ne m'en sors pas pour l'instant.

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Citation Envoyé par dingoth Voir le message
    Je viens de trouver cette regex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String regex = "(^|\\.)AAA(\\.[^(AAA|BBB|CCC|[^\\.]+)])*\\.$";
    Elle signifie, trouve un A qui soit suivi par un point, puis par un nombre quelconque de champ qui ne comportent pas de lettre et sont différents de B ou C. Dans tous les cas, il faut un point en dernier caractère. La deuxième présence de A force le moteur de regex à prendre le dernier A visible. Le premier point est un délimiteur, interdisant de matcher A comme faisant partie d'un mot complet (FA, par exemple).
    Celle-ci le fait. Enfin, presque : j'y ai vu une faute. Voici le corrigé :

    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
    String regex =
       "(^|\\.)"      // Début de chaîne ou un point
     + "AAA"          // La chaîne à matcher
     + "("            // On peut éventuellement trouver le groupe suivant.
       + "\\."        // S'il y a quelque chose après le AAA, ce doit être un point.
       + "[^("        // On récupère tout sauf...
         + "AAA"      // La chaîne qu'on veut
         + "|" 
         + "BBB"      // La chaîne BBB qu'on ne veut PAS
         + "|"
         + "CCC"      // La chaîne CCC qu'on ne veut PAS
         + "|"
         + ".*?\\..*" // Quelque chose d'autre qui contient un point.
       + ")]"         // Fin du groupe de subpatterns qu'on ne veut pas
     + ")*"           // Fin du groupe, on répète entre 0 et n fois.
     + "\\.$"         // Le dernier caractère doit être un point.
    ;

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Malheureusement le construct [^ ne permet que la négation de caractères, pas de chaines de caractères et donc ca ne marche pas...

    En effet, [^(BBB)] ne comprend pas BBB comme la chaine BBB mais comme 3 caractères et il interprète comme "je ne dois pas tomber sur la lettre B".

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Autre point, si .BBB. doit empêcher le match, .BBBbbb. ne doit pas l'empêcher

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par mpawlak Voir le message
    1) A, B ou C sont une substring d'un nom de package (des chaines de caractère donc et non pas un caractère unique. Nommons les donc AAA, BBB, CCC pour que ceci soit plus clair.
    ...
    le problème c'est qu'on ne peut pas faire la négation d'une chaîne de caractères, et quel que soit le sens dans lequel j'ai tourné ton problème, je suis toujours tombée sur une négation de chaîne (avec une chaîne réduite à un caractère évidemment ça devenait plus facile)

  11. #11
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Oulalala ! Monsieur est difficile ! Voyons voir si nous parvenons à le satisfaire. (Attention, je ne teste plus, là...)

    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
    String regex =
       "(^|\\.)"        // Début de chaîne ou un point
     + "AAA"            // La chaîne à matcher
     + "("              // On peut éventuellement trouver le groupe suivant.
       + "\\."          // S'il y a quelque chose après le AAA, ce doit être un point.
       + "(?:"          // Nouveau groupe, non capturant pour tester le premier caractère
         + "[^ABC.]"     // On interdit le B, le C et le .
         + "|"
         + "A(?!AA\\.)" // Mais si on trouve un A, alors il ne peut être suivi de AA et d'un point. Non, on veut surtout pas un autre AAA ici.
         + "|"
         + "B(?!BB\\.)" // Mais si on trouve un B, alors il ne peut être suivi de BB et d'un point.
         + "|"
         + "C(?!CC\\.)" // Et si on trouve un C, alors il ne peut être suivi de CC et d'un point.
       + ")"            // Fin du groupe exclusif pour les premiers caractères suivant le . qui suit le AAA.
       + ".*?"          // Après ce groupe, on peut avoir n'importe quel caractère en mode reluctant pour récupérer le prochain point.
     + ")*"             // Fin du groupe, on répète entre 0 et n fois.
     + "\\.$"           // Le dernier caractère doit être un point.
    ;
    Là, j'ai épuisé toutes mes cartouches... Si ça marche pas, j'abandonne.

    Par contre, algorithmiquement parlant, j'ai déjà une bonne solution.

  12. #12
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    On y est presque...
    Avec :

    ^((?:.+\.)*AAA)(\.(?:[^BC.]|B(?!BB\.)|C(?!CC\.)).*?)*\.$

    Comme je le désire, les 4 strings suivants ne matchent pas :

    xxxxxx.AAA.BBB.
    xxxxxx.AAA.BBB.xxxxxx.
    xxxxxx.AAA.CCC.
    xxxxxx.AAA.CCC.xxxxxx.

    Par contre ceux-ci matchent alors qu'ils ne devraient pas :

    xxxxxx.AAA.xxxxxx.BBB.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.
    xxxxxx.AAA.xxxxxx.CCC.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.BBB.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.BBB.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.CCC.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.CCC.xxxxxx.

    Le problème vient du fait qu'il y a des xxxxxx devant les BBB ou CCC

    Enfin, ceux-ci matchent correctement.

    xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.
    xxxxxx.AAA.xxxxxx.BBB.xxxxxx.AAA.xxxxxx.
    xxxxxx.AAA.xxxxxx.CCC.xxxxxx.AAA.xxxxxx.

    Dans les cas qui me posent problème, le groupe 2 est :

    xxxxxx.BBB.
    xxxxxx.BBB.xxxxxx.
    xxxxxx.CCC.
    xxxxxx.CCC.xxxxxx.

    J'ai donc essayé avec la regexp suivante :

    ^((?:.+\.)*AAA)(\.(?:[^BC]|B(?!BB\.)|C(?!CC\.))\w*)*\.$

    En gros : je ne veux pas qu'un nom commence par B ou C, si ce n'est pas le cas après j'ai un ensemble de caractères a-zA-Z0-9, par contre si c'est le cas ca ne doit pas être BBB ou CCC

    Et je crois les doigts mais il semblerait que cela joue...

    Je dois encore faire des tests plus poussés, si qqun a une remarque je suis preneur.

    Encore merci,

    MP.

  13. #13
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    As-tu utilisé ma regex ? J'ai l'impression que tu cherches à créer la tienne à partir des nôtres sans les tester...

    Parce que, j'ai bel et bien mis (^|\\.) en entrée pour une raison, pas pour faire joli, tout comme le AAA dans la négation.

    À la rigueur modifier mon ".*?" en "[^.]*" pourrait être envisageable, mais le reste est indispensable (le . dans le [^ABC.] également).

    De plus, dans ta dernière regex, tu autorises le "xxx.AAA..", ce que je ne fais jamais.

  14. #14
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    je t'assure que moi non plus si j'ai fais des changements ce n'était pas "pour faire joli" mais pour des contraintes réelles (genre une chaîne de caractères entre ^ et AAA)... Je trouve ton dernier message particulièrement agressif voir même gamin "tu n'as pas utilisé MA regexp".

    Pour te répondre : oui j'ai bien testé tes regexp à chaque fois avec quickrex et un jeu de données test, mais aucune n'a matché tous mes cas de test.

    Mais passons, j'ai obtenu mon modèle de regexp qui m'a permis d'en pondre une 10aine d'autres, et ce en grande partie grace à tes remarques et je t'en remercie.

    Dommage que le thread se finisse ainsi.

    Citation Envoyé par dingoth Voir le message
    As-tu utilisé ma regex ? J'ai l'impression que tu cherches à créer la tienne à partir des nôtres sans les tester...

    Parce que, j'ai bel et bien mis (^|\\.) en entrée pour une raison, pas pour faire joli, tout comme le AAA dans la négation.

    À la rigueur modifier mon ".*?" en "[^.]*" pourrait être envisageable, mais le reste est indispensable (le . dans le [^ABC.] également).

    De plus, dans ta dernière regex, tu autorises le "xxx.AAA..", ce que je ne fais jamais.

  15. #15
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Décidément, j'aide et ça part en cou****...

    'fin soit, non, je n'étais pas du tout agressif. En voyant à chaque fois ta regex, j'avais l'impression que tu faisais les modifications sans comprendre pourquoi j'avais mis telle ou telle expression faisant un travail essentiel dans l'expression générale, et que donc, bah ça foirait, puisque tu changeais mon pattern sans le tester au préalable, simplement en prenant ce que tu estimais de bon dedans.

    Heureux toutefois que tu aies trouvé la solution. Si je puis me permettre, pourrais-tu écrire ton expression finale ci-dessous et marquer le sujet comme lu ?

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

Discussions similaires

  1. petit problème d'expression régulière
    Par stoyak dans le forum Langage
    Réponses: 5
    Dernier message: 16/05/2006, 11h20
  2. [regexp] petit problème d'expression régulière
    Par LE NEINDRE dans le forum Langage
    Réponses: 14
    Dernier message: 16/12/2005, 10h33
  3. Problème d'expression régulière
    Par SiM07 dans le forum Langage
    Réponses: 2
    Dernier message: 02/12/2005, 17h57
  4. Problème d'expression régulière
    Par Pymm dans le forum Général JavaScript
    Réponses: 15
    Dernier message: 11/10/2005, 15h04
  5. Problème d'expression régulière
    Par Neitsa dans le forum Général Python
    Réponses: 3
    Dernier message: 11/08/2005, 14h29

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