Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Trouver toutes les occurrences d'une regexp (et seulement elles) en Java

12 réponses
Avatar
Olivier Miakinen
[diapublication entre fr.comp.lang.regexp et fr.comp.lang.java, suivi
vers fr.comp.lang.java seul]

Bonjour,

Pour une fois c'est moi qui vais poser une question de regexp, parce
qu'en Java je suis un peu perdu entre les méthodes matches, find et
lookingAt de la classe Matcher.

Soit une chaîne telle que celle-ci :
String s = "<ABC> <AABBA> <CBCC> <ABB> <C> ";

Je voudrais en extraire les sous-chaînes successives :
"ABC", "AABBA", "CBCC", "ABB" et "C".

Pour ce faire, je pense donc utiliser le Pattern suivant :
Pattern p = Pattern.compile("<([ABC]*)> ");
puis :
Matcher m = p.matcher(s);

Mais ce n'est pas tout : je voudrais pouvoir détecter si la chaîne
contient autre chose que ce que je compte y trouver. Par exemple,
la rechercher doit échouer si la chaîne de départ vaut :
String s = "<ABC> <AABBA> <CBCC> foo <ABB> <C> ";
mais aussi si elle vaut :
String s = "<ABC> <AABBA> <CBCC> <ABB> <C> bar";

Comment devrais-je m'y prendre ?

Cordialement,
--
Olivier Miakinen

10 réponses

1 2
Avatar
Samuel DEVULDER
Le 20/10/2017 à 01:04, Olivier Miakinen a écrit :
Comment devrais-je m'y prendre ?

Une boucle! Tant que "ca match", tu récupère le matching, et tu remplace
la chaine matchée par la chaine vide. En sortie de boucle la chaine
finale doit être vide. Sinon c'est qu'elle contenait des trucs.
C'est pas la méthode la plus rapide, mais ca marche.
a+
sam.
Avatar
Olivier Miakinen
Le 20/10/2017 08:38, Samuel DEVULDER a écrit :
Comment devrais-je m'y prendre ?

Une boucle! Tant que "ca match", tu récupère le matching,

Euh... oui, c'est bien ce que je pensais faire, mais...
et tu remplace la chaine matchée par la chaine vide.

Ah oui, pas bête du tout, je n'y avais pas pensé. Il suffit
de faire un truc du genre s = s.substring(m.group(0).length())
et d'utiliser m.group(1).
En sortie de boucle la chaine
finale doit être vide. Sinon c'est qu'elle contenait des trucs.
C'est pas la méthode la plus rapide, mais ca marche.

Ok. Je vais attendre de voir s'il existe une autre méthode plus
simple ou plus efficace, mais sinon c'est bien celle-ci que
j'utiliserai. Merci !
--
Olivier Miakinen
Avatar
Olivier Miakinen
Le 20/10/2017 10:00, je répondais à Samuel Devulder :
Une boucle! Tant que "ca match", tu récupère le matching,
et tu remplace la chaine matchée par la chaine vide.

Ah oui, pas bête du tout, je n'y avais pas pensé. Il suffit
de faire un truc du genre s = s.substring(m.group(0).length())
et d'utiliser m.group(1).

Finalement, j'ai utilisé ta méthode :
Pattern p = ...
String s = ...
while (! s.isEmpty()) {
Matcher m = p.matcher(s);
if (! m.lookingAt()) {
... ERREUR ...
}
... utiliser m.group(1) ...
s = s.substring(m.end());
}
Merci !
--
Olivier Miakinen
Avatar
Samuel DEVULDER
Tout compte fait c'était pas un pb de java mais un pb d'algo. Le même
algo existe en perl, ou en C si on veut résoudre les mêmes problèmes
dans ces langages.
Avatar
Elhwen Dico
Le 20/10/2017 à 19:41, Samuel DEVULDER a écrit :
Tout compte fait c'était pas un pb de java mais un pb d'algo. Le même
algo existe en perl, ou en C si on veut résoudre les mêmes problèmes
dans ces langages.

Oui, ben ça fait plaisir que le groupe vive encore. Je commençais à
désespérer...
Avatar
Olivier Miakinen
Le 20/10/2017 19:41, Samuel DEVULDER a écrit :
Tout compte fait c'était pas un pb de java mais un pb d'algo. Le même
algo existe en perl, ou en C si on veut résoudre les mêmes problèmes
dans ces langages.

C'était quand même une question spécifique à Java, puisque la solution
que j'ai retenue utilise lookingAt() et que ça n'aurait pas fonctionné
avec find() -- à moins d'ancrer la regexp à gauche mais pas à droite --
ni surtout avec matches() -- avec ou sans ancrage.
Je ne sais d'ailleurs pas si l'équivalent existe en perl et en C.
--
Olivier Miakinen
Avatar
Elhwen Dico
Le 20/10/2017 à 18:23, Olivier Miakinen a écrit :
Le 20/10/2017 10:00, je répondais à Samuel Devulder :
Une boucle! Tant que "ca match", tu récupère le matching,
et tu remplace la chaine matchée par la chaine vide.

Ah oui, pas bête du tout, je n'y avais pas pensé. Il suffit
de faire un truc du genre s = s.substring(m.group(0).length())
et d'utiliser m.group(1).

Finalement, j'ai utilisé ta méthode :
Pattern p = ...
String s = ...
while (! s.isEmpty()) {
Matcher m = p.matcher(s);
if (! m.lookingAt()) {
... ERREUR ...
}
... utiliser m.group(1) ...
s = s.substring(m.end());
}
Merci !

Sinon, j'ai trouvé ça aussi.
public class RegexpMain {
private static final String SPLIT =
"(s+)|((?<=>)(?!s))|((?<!s)(?=<))";
private static final String PARSE = "<([w]*)>";
private static final Pattern PARSE_PATTERN = Pattern.compile(PARSE);
private static final String cmdstr = "<command1> <command2>
<command3<command4><command5 command6 <command7><command8>";
public static void main(String[] args) {
String[] cmds = cmdstr.split(SPLIT);
for (String cmd : cmds) {
Matcher matcher = PARSE_PATTERN.matcher(cmd);
if (matcher.matches()) {
String trusted = matcher.group(1);
System.out.printf("trouvé : %s%n", trusted);
} else {
System.out.printf("Erreur de syntaxe "%s"%n", cmd);
}
}
}
}
Sortie:
trouvé : command1
trouvé : command2
Erreur de syntaxe "<command3"
trouvé : command4
Erreur de syntaxe "<command5"
Erreur de syntaxe "command6"
trouvé : command7
trouvé : command8
On split la chaine de caracteres pour séparer les commandes. Ensuite
on vérifie que chaque commande est correctement formattée. Le split
decoupe soit aux espaces, soit si il y a un "<" ou ">".
Avatar
Olivier Miakinen
Le 21/10/2017 19:00, Elhwen Dico m'a répondu :
Sinon, j'ai trouvé ça aussi.
[...]
On split la chaine de caracteres pour séparer les commandes. Ensuite
on vérifie que chaque commande est correctement formattée. Le split
decoupe soit aux espaces, soit si il y a un "<" ou ">".

En effet, et ça aurait fonctionné dans l'exemple que j'avais donné
avec des "<AABBA>". Mais j'avais simplifié mon exemple pour ne pas
encombrer ma question de détails superflus.
En réalité, ma chaîne ressemble plus à :
"( coerce (list 1 2 3 5 ) oid) (coerce ( list 0 0) oid ) (coerce
(list 1 3 6 1 2 1) oid) (coerce (list 2 0 12 1 125 ) oid) "
et la regexp à trouver N fois :
"( *coerce +( *list +([0-9 ]+)) *oid *) *"
Le résultat devant être :
"1 2 3 5 " / "0 0" / "1 3 6 1 2 1" / "2 0 12 1 125 "
(et oui, c'est bien en Java que je dois le lire et non en Lisp...)
--
Olivier Miakinen
Avatar
Samuel DEVULDER
Le 21/10/2017 à 21:56, Olivier Miakinen a écrit :
(et oui, c'est bien en Java que je dois le lire et non en Lisp...)

lisp... qui porte toujours très bien son acronyme: Lots of Insipid
ParenthesiS :) :) :) :)
Avatar
Yliur
Le Sat, 21 Oct 2017 23:24:01 +0200
Samuel DEVULDER a écrit :
Le 21/10/2017 à 21:56, Olivier Miakinen a écrit :
(et oui, c'est bien en Java que je dois le lire et non en Lisp...)

lisp... qui porte toujours très bien son acronyme: Lots of Insipid
ParenthesiS :) :) :) :)

Hum... Ton développement ne marche pas, ce n'est pas "Lips" mais Lisp.
Et le développement "correct" est "Lots of Irritating Superfluous
Parentheses".
Ceci étant dit, l'exemple d'Olivier ne contient pas tellement de
parenthèses, il n'est juste pas indenté parce qu'on n'en a qu'un
fragment, pace qu'il s'agit de code généré, parce qu'il a trouvé
que ce serait plus simple de l'écrire sur une seule ligne, parce
qu'il ne voulait pas que la chaîne soit "propre" mais pleine de
variations que son expression doit capturer malgré tout, ... (barrez
les mentions inutiles) :
(coerce (list 1 2 3 5 ) oid)
(coerce (list 0 0) oid)
(coerce (list 1 3 6 1 2 1) oid)
(coerce (list 2 0 12 1 125) oid)
Et dans cet exemple il n'y a pas plus de parenthèses qu'en java : une
fonction pour créer des listes nommée "list" s'écrirait comme ça en
java :
list (1 2 3 5)
au lieu de :
(list 1 2 3 5)
Pour "coerce", même chose si c'est une fonction, ou bien ce serait un
transtypage et ça s'écrirait :
(oid) ...
(autant de parenthèses en java, mais le mot-clé en moins)
Pire, les transtypages nécessitent régulièrement une paire de
parenthèses en plus en java, du style :
((String) fonction-renvoyant-un-Object (...)).length()
Sinon c'est indiscret de demander à Olivier ce qu'il fait avec du code
Lisp ? Une traduction d'un code dans un autre langage ?
1 2