[Java] Pattern, (non-)capturing groupes
Fermé
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
-
1 oct. 2011 à 16:35
heyquem Messages postés 759 Date d'inscription mercredi 17 juin 2009 Statut Membre Dernière intervention 29 décembre 2013 - 3 oct. 2011 à 00:14
heyquem Messages postés 759 Date d'inscription mercredi 17 juin 2009 Statut Membre Dernière intervention 29 décembre 2013 - 3 oct. 2011 à 00:14
A voir également:
- [Java] Pattern, (non-)capturing groupes
- Waptrick java football - Télécharger - Jeux vidéo
- Jeux java itel football - Télécharger - Jeux vidéo
- Java apk - Télécharger - Langages
- Waptrick java voiture - Télécharger - Jeux vidéo
- Java décompiler - Télécharger - Langages
3 réponses
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
3 020
1 oct. 2011 à 21:33
1 oct. 2011 à 21:33
J'ai un petit peu avancé dans mon problème, mais rien encore de vraiment concluant...
Lorsque j'utilise Matcher, le groupCount est toujours identique pour un Pattern donné, et ce indépendamment de la chaîne de caractères parsé. Or j'utilises des quantificateurs ? + et * mais ceux-ci ne semblent pas agir....
Ainsi dans mes tests 5 avec "(X)?(?:(?:Y)(Z))*", j'aurai toujours deux résultats, correspondant à X et Z.
Cependant si le groupe n'est pas matché (pour X ou Z) j'obtient null, et s'il est matché plusieurs fois (pour Z) la valeur du groupe est écrasée au fur et à mesure pour ne conserver que la dernière !
Bref, ça ne marche pas, et j'aurais bien besoin d'un petit coup de main si quelqu'un s'y connaît ;-)
Lorsque j'utilise Matcher, le groupCount est toujours identique pour un Pattern donné, et ce indépendamment de la chaîne de caractères parsé. Or j'utilises des quantificateurs ? + et * mais ceux-ci ne semblent pas agir....
Ainsi dans mes tests 5 avec "(X)?(?:(?:Y)(Z))*", j'aurai toujours deux résultats, correspondant à X et Z.
Cependant si le groupe n'est pas matché (pour X ou Z) j'obtient null, et s'il est matché plusieurs fois (pour Z) la valeur du groupe est écrasée au fur et à mesure pour ne conserver que la dernière !
Bref, ça ne marche pas, et j'aurais bien besoin d'un petit coup de main si quelqu'un s'y connaît ;-)
private static void test(int id,String regex,String exemple) { System.out.println("Test "+id+" "+exemple.matches(regex)); Matcher matcher = Pattern.compile(regex).matcher(exemple); matcher.find(); for (int i=1, n=matcher.groupCount(); i<=n; i++) System.out.println("\t"+matcher.group(i)); } private static void essai() { String modifier = "(?:(?:[\\<]?[\\w]+[\\>]?[\\s]+)*)"; test(11,modifier,"public abstract <E> "); String pack = "(?:(?:[\\w]+[\\.]+)*)"; test(21,pack,"java.util."); String classe = "(?:"+pack+"[\\w]+"+")"; test(31,classe,"java.util.Collection"); String type = "(?:"+classe+"(?:[\\<](?:[\\?][\\s]+extends[\\s]+)?"+classe+"[\\>])?(?:\\[\\])*)"; test(41,type,"int"); test(42,type,"java.lang.String[][]"); test(43,type,"java.util.Collection<E>"); test(44,type,"java.util.Collection<? extends E>[]"); String param = "\\(("+type+")?(?:(?:[\\s]*\\,[\\s]*)("+type+"))*\\)"; test(51,param,"()"); test(52,param,"(int)"); test(53,param,"(float,double)"); test(54,param,"(char,byte,short)"); }
heyquem
Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
131
2 oct. 2011 à 00:56
2 oct. 2011 à 00:56
salut KX
Je ne comprends le problème tel que tu l'exposes
Il faut dire que je ne connais pas Java
Pourrais tu réduire ton problème à sa plus simple expression: plusieurs chaînes, et dire ce que tu veux en extraire avec une regex.
Je ne comprends le problème tel que tu l'exposes
Il faut dire que je ne connais pas Java
Pourrais tu réduire ton problème à sa plus simple expression: plusieurs chaînes, et dire ce que tu veux en extraire avec une regex.
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
3 020
2 oct. 2011 à 11:15
2 oct. 2011 à 11:15
Merci heyquem de me répondre,
Ce que je veux c'est récupérer (entre autre) chaque types pris en paramètre d'une fonction.
Ces types peuvent être assez compliqués par exemple "java.util.Collection<? extends E>[]" mais pour simplifier on n'a qu'à dire que ce sont des mots \w+ et je veux les capturer.
Les différents types sont séparés par des virgules avec éventuellement des espaces avant ou après, là encore simplifions en disant qu'il n'y a que des espaces \s+ mais que je ne veux pas capturer.
Exemples :
En Java (j'ignore si c'est pareil dans les autres langages) quand on veut capturer un groupe X, on le note entre parenthèses (X) et quand on ne veut pas le capturer on fait (?:X)
Mon expression régulière commence par (\w+)? pour prendre 0 ou 1 fois les premieres lettres, c'est à dire sans aucun espace derrière (pour matcher 1 et 2)
Suivi de 0 ou plusieurs fois un bloc B que je ne capture pas (?:B)* avec B qui est la succession d'1 ou plusieurs espaces que je ne capture pas (?:\s+) et d'une ou plusieurs lettres que je capture (\w+)
Au final j'ai donc une expression régulière comme ceci: (\w+)?(?:(?:\s+)(\w+))*
Avec cette expression régulière mes quatre exemples sont bien matchés. Le problème c'est qu'au moment de récupérer les groupes avec les outils Java, je récupère toujours 2 groupes, correspondant à chacun des deux blocs que j'ai mis en gras dans l'expression régulière. Avec la valeur null lorsqu'on est dans le cas 0 fois (pour ? et *) et la dernière valeur lorsqu'on est dans le cas plusieurs fois (pour *)
C'est à dire que mes exemples donnent :
Et pour info, le code Java correspondant est celui-ci :
Je ne sais pas si c'est vraiment plus simple à comprendre comme ceci, parce que même en simplifiant ça reste quand même assez compliqué... Sinon j'y serais surement arrivé moi même mais là je bloque :(
Pour information, je suis "obligé" d'utiliser le langage Java, puisque c'est pour permettre de parser le nom des méthodes, c'est à dire retrouver une méthode Java existante en lui donnant la chaîne de caractères correspondante.
Exemple : je tape au clavier "public void java.io.PrintStream.println(char[])" et le programme me permet de retrouver la méthode spécifié et ainsi l'invoquer dynamiquement...
Ce que je veux c'est récupérer (entre autre) chaque types pris en paramètre d'une fonction.
Ces types peuvent être assez compliqués par exemple "java.util.Collection<? extends E>[]" mais pour simplifier on n'a qu'à dire que ce sont des mots \w+ et je veux les capturer.
Les différents types sont séparés par des virgules avec éventuellement des espaces avant ou après, là encore simplifions en disant qu'il n'y a que des espaces \s+ mais que je ne veux pas capturer.
Exemples :
1) "" --> {} 2) "int" --> {"int"} 3) "float double" --> {"float","double"} 4) "char byte short" --> {"char","byte","short"}
En Java (j'ignore si c'est pareil dans les autres langages) quand on veut capturer un groupe X, on le note entre parenthèses (X) et quand on ne veut pas le capturer on fait (?:X)
Mon expression régulière commence par (\w+)? pour prendre 0 ou 1 fois les premieres lettres, c'est à dire sans aucun espace derrière (pour matcher 1 et 2)
Suivi de 0 ou plusieurs fois un bloc B que je ne capture pas (?:B)* avec B qui est la succession d'1 ou plusieurs espaces que je ne capture pas (?:\s+) et d'une ou plusieurs lettres que je capture (\w+)
Au final j'ai donc une expression régulière comme ceci: (\w+)?(?:(?:\s+)(\w+))*
Avec cette expression régulière mes quatre exemples sont bien matchés. Le problème c'est qu'au moment de récupérer les groupes avec les outils Java, je récupère toujours 2 groupes, correspondant à chacun des deux blocs que j'ai mis en gras dans l'expression régulière. Avec la valeur null lorsqu'on est dans le cas 0 fois (pour ? et *) et la dernière valeur lorsqu'on est dans le cas plusieurs fois (pour *)
C'est à dire que mes exemples donnent :
1) "" --> {null,null} 2) "int" --> {"int",null} 3) "float double" --> {"float","double"} 4) "char byte short" --> {"char","short"}
Et pour info, le code Java correspondant est celui-ci :
public static void main(String...args) { String regex = "(\\w+)?(?:(?:\\s+)(\\w+))*"; simple(regex,""); simple(regex,"int"); simple(regex,"float double"); simple(regex,"char byte short"); } private static void simple(String regex,String exemple) { Matcher matcher = Pattern.compile(regex).matcher(exemple); matcher.find(); System.out.print(exemple+"\t{"); for (int i=1, n=matcher.groupCount(); i<=n; i++) System.out.print(matcher.group(i)+" "); System.out.println("}"); }
Je ne sais pas si c'est vraiment plus simple à comprendre comme ceci, parce que même en simplifiant ça reste quand même assez compliqué... Sinon j'y serais surement arrivé moi même mais là je bloque :(
Pour information, je suis "obligé" d'utiliser le langage Java, puisque c'est pour permettre de parser le nom des méthodes, c'est à dire retrouver une méthode Java existante en lui donnant la chaîne de caractères correspondante.
Exemple : je tape au clavier "public void java.io.PrintStream.println(char[])" et le programme me permet de retrouver la méthode spécifié et ainsi l'invoquer dynamiquement...
heyquem
Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
131
Modifié par heyquem le 2/10/2011 à 19:03
Modifié par heyquem le 2/10/2011 à 19:03
Je ne vais pas répondre à ta fausse question , mais à la vraie.
Je veux dire que ta question relève à mon avis du problème XY:
https://meta.stackexchange.com/questions/56366/can-we-get-people-to-directly-ask-about-their-problems-instead-of-topics-they-thi
Je crois en effet que tu t'es compliqué la vie
1/ en te persuadant qu'il te fallait définir deux groupes
2/ en essayant de capturer une succession des groupes dans la chaîne analysée avec le deuxième groupe de la regex quantifié avec *
Mais tu es ainsi parti sur une fausse piste
Pensant avoir compris ce que tu veux, je préfère raisonner sur le problème réel, plutôt que de considérer les deux simplifications que tu proposes (des mots \w+ à la place des types compliqués, et des blancs à la place de virgule+blancs).
En Python, cela donne ce qui suit. Excuse moi, mais je ne connais que Python
findall(x) et [ mat.group(1) for mat in regx.finditer(x)] ont le même résultat; c'est voulu, dans mon code: si on ne veut que la liste des groupes capturés, on utilise findall(); si on veut faire des traitements sur les groupes capturés, on y accède en itérant progressivement avec finditer()
Le résultat est :
La regex située plus haut extrait les types même si la liste de paramètres est incorrecte:
par exemple
On pourra améliorer la regex si tu veux la rendre telle qu'elle puisse aussi valider la chaîne de paramètres
Je veux dire que ta question relève à mon avis du problème XY:
https://meta.stackexchange.com/questions/56366/can-we-get-people-to-directly-ask-about-their-problems-instead-of-topics-they-thi
Je crois en effet que tu t'es compliqué la vie
1/ en te persuadant qu'il te fallait définir deux groupes
2/ en essayant de capturer une succession des groupes dans la chaîne analysée avec le deuxième groupe de la regex quantifié avec *
Mais tu es ainsi parti sur une fausse piste
Pensant avoir compris ce que tu veux, je préfère raisonner sur le problème réel, plutôt que de considérer les deux simplifications que tu proposes (des mots \w+ à la place des types compliqués, et des blancs à la place de virgule+blancs).
En Python, cela donne ce qui suit. Excuse moi, mais je ne connais que Python
findall(x) et [ mat.group(1) for mat in regx.finditer(x)] ont le même résultat; c'est voulu, dans mon code: si on ne veut que la liste des groupes capturés, on utilise findall(); si on veut faire des traitements sur les groupes capturés, on y accède en itérant progressivement avec finditer()
regx = re.compile('(?:\A|,) *([^,]+?)(?:(?<! ) *?(?=,|\Z))') for chaine_de_parametres in (""," ", "int"," int","int "," int ", "float,double", "float, double","float ,double","float , double", " float,double"," float, double"," float ,double"," float , double", "float,double ","float, double ","float ,double ","float , double ", " float,double "," float, double "," float ,double "," float , double ", "char,byte,short", "char ,byte,short","char, byte,short","char , byte,short", "char,byte ,short","char,byte, short","char,byte , short", "char ,byte, short","char ,byte ,short", "char, byte , short"," char , byte, short", " char, byte,short "," char, byte ,short " ," char , byte, short ", "char, byte , short "," char ,byte, short ","char , byte, short", "java.util.Collection<? extends E>[], char , byte", " int, java.util.Collection<? extends E>[], char byte"): print 'chaine_de_parametres == ', repr(chaine_de_parametres) print regx.findall(chaine_de_parametres) print [ mat.group(1) for mat in regx.finditer(chaine_de_parametres)] print
Le résultat est :
chaine_de_parametres == '' [] [] chaine_de_parametres == ' ' [] [] chaine_de_parametres == 'int' ['int'] ['int'] chaine_de_parametres == ' int' ['int'] ['int'] chaine_de_parametres == 'int ' ['int'] ['int'] chaine_de_parametres == ' int ' ['int'] ['int'] chaine_de_parametres == 'float,double' ['float', 'double'] ['float', 'double'] chaine_de_parametres == 'float, double' ['float', 'double'] ['float', 'double'] chaine_de_parametres == 'float ,double' ['float', 'double'] ['float', 'double'] chaine_de_parametres == 'float , double' ['float', 'double'] ['float', 'double'] .... etc chaine_de_parametres == ' float,double ' ['float', 'double'] ['float', 'double'] chaine_de_parametres == ' float, double ' ['float', 'double'] ['float', 'double'] chaine_de_parametres == ' float ,double ' ['float', 'double'] ['float', 'double'] chaine_de_parametres == ' float , double ' ['float', 'double'] ['float', 'double'] chaine_de_parametres == 'char,byte,short' ['char', 'byte', 'short'] ['char', 'byte', 'short'] chaine_de_parametres == 'char ,byte,short' ['char', 'byte', 'short'] ['char', 'byte', 'short'] chaine_de_parametres == 'char, byte,short' ['char', 'byte', 'short'] ['char', 'byte', 'short'] ....... etc chaine_de_parametres == 'char, byte , short ' ['char', 'byte', 'short'] ['char', 'byte', 'short'] chaine_de_parametres == ' char ,byte, short ' ['char', 'byte', 'short'] ['char', 'byte', 'short'] chaine_de_parametres == 'char , byte, short' ['char', 'byte', 'short'] ['char', 'byte', 'short'] chaine_de_parametres == 'java.util.Collection<? extends E>[], char , byte' ['java.util.Collection<? extends E>[]', 'char', 'byte'] ['java.util.Collection<? extends E>[]', 'char', 'byte'] chaine_de_parametres == ' int, java.util.Collection<? extends E>[], char byte' ['int', 'java.util.Collection<? extends E>[]', 'char byte'] ['int', 'java.util.Collection<? extends E>[]', 'char byte']
La regex située plus haut extrait les types même si la liste de paramètres est incorrecte:
par exemple
' , , char , byte, short'doit être incorrecte, je pense, mais la regex parvient à extraire les types.
On pourra améliorer la regex si tu veux la rendre telle qu'elle puisse aussi valider la chaîne de paramètres
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
3 020
2 oct. 2011 à 19:15
2 oct. 2011 à 19:15
Je ne connais pas Python et pour le coup c'est moi qui ne comprends pas ^^
Je crois que ce que tu fais c'est simplement utiliser la virgule comme délimiteur de chaque champ, tu découpes à la virgule et tu prends les groupes les uns après les autres.
Le problème c'est que dans mes types je peux avoir des virgules aussi, par exemple "Map<K,V>"
Et que si je dois parser "Map<K,V>" je pense que tes regex vont renvoyer "Map<K" et "V>"
Je crois que ce que tu fais c'est simplement utiliser la virgule comme délimiteur de chaque champ, tu découpes à la virgule et tu prends les groupes les uns après les autres.
Le problème c'est que dans mes types je peux avoir des virgules aussi, par exemple "Map<K,V>"
Et que si je dois parser "Map<K,V>" je pense que tes regex vont renvoyer "Map<K" et "V>"
heyquem
Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
131
2 oct. 2011 à 19:42
2 oct. 2011 à 19:42
Ne pas comprendre Python ? oh oh oh, ah ah ah , je ne le crois pas
L'essentiel est de toutes façons le pattern de la regex:
"Je crois que ce que tu fais c'est simplement utiliser la virgule comme délimiteur de chaque champ"
Tout à fait.
Mais comme je me doutais bien que le principe de délimiter selon la virgule risquait d'être insuffisant, je n'ai pas utilisé un simple splitting, mais une regex qu'il faut donc maintenant améliorer, tout simplement.
S'il peut y avoir des virgules au sein des types, comment Java distingue-t-il si une virgule est à l'intérieur d'un type ou une séparatrice de types ?
J'ai jeté un coup d'oeil sur la page de Method.toGenericString() que tu as indiquée, mais je n'y vois pas de types avec des virgules internes.
Pourrais tu donner plusieurs chaînes de paramètres, de façon à ce que je saisisse le principe de leur écriture.
Est-ce que les types sont toujours entourés de double quotes ?
L'essentiel est de toutes façons le pattern de la regex:
'(?:\A|,) *([^,]+?)(?:(?<! ) *?(?=,|\Z))'
"Je crois que ce que tu fais c'est simplement utiliser la virgule comme délimiteur de chaque champ"
Tout à fait.
Mais comme je me doutais bien que le principe de délimiter selon la virgule risquait d'être insuffisant, je n'ai pas utilisé un simple splitting, mais une regex qu'il faut donc maintenant améliorer, tout simplement.
S'il peut y avoir des virgules au sein des types, comment Java distingue-t-il si une virgule est à l'intérieur d'un type ou une séparatrice de types ?
J'ai jeté un coup d'oeil sur la page de Method.toGenericString() que tu as indiquée, mais je n'y vois pas de types avec des virgules internes.
Pourrais tu donner plusieurs chaînes de paramètres, de façon à ce que je saisisse le principe de leur écriture.
Est-ce que les types sont toujours entourés de double quotes ?
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
3 020
Modifié par KX le 2/10/2011 à 19:59
Modifié par KX le 2/10/2011 à 19:59
En fait quand il y a des virgules elles sont entourées par des <>
Les types ne sont pas entourés par les guillemets, mais comme je manipule des chaînes de caractères je les mets.
Par exemple toGenericString() donne des choses de cette forme :
public void java.util.AbstractMap.putAll(java.util.Map.<? extends K,? extends V>)
Le problème c'est qu'en construisant ses propres méthodes ça peut se complexifier :
Autre comportement particulier, il y a les [] qui peuvent se rajouter à n'importe quel type mais il ne sont pas trop gênants.
Les types ne sont pas entourés par les guillemets, mais comme je manipule des chaînes de caractères je les mets.
Par exemple toGenericString() donne des choses de cette forme :
public void java.util.AbstractMap.putAll(java.util.Map.<? extends K,? extends V>)
Le problème c'est qu'en construisant ses propres méthodes ça peut se complexifier :
public java.util.Map<? extends K,? extends W> fusion(java.util.Map<java.util.Map<? extends K,? extends V>,java.util.Map<? extends V,? extends W>>)
Autre comportement particulier, il y a les [] qui peuvent se rajouter à n'importe quel type mais il ne sont pas trop gênants.
heyquem
Messages postés
759
Date d'inscription
mercredi 17 juin 2009
Statut
Membre
Dernière intervention
29 décembre 2013
131
2 oct. 2011 à 20:05
2 oct. 2011 à 20:05
public java.util.Map<? extends K,? extends W> fusion
c'est la déclaration et le nom de la fonction ?
est ce que ça se trouve dans la chaîne qui est soumise à l'examen par la regex ?
KX
Messages postés
16755
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
12 février 2025
3 020
Modifié par KX le 2/10/2011 à 20:08
Modifié par KX le 2/10/2011 à 20:08
Au final oui, je passerai tout à parser, mais cette partie là n'est pas très compliquée parce que j'ai un nombre fixe de groupes à récupérer, donc je n'ai pas de problème.