Aller au contenu

[Résolu] Pattern récursif dans une expression régulière


Nozalys

Messages recommandés

Bonjour,

Je bloque sur une regex un peu particulière :

Voici une chaine de caractère type : " -59.99 -46.54 -25.59 -25.09 -25.51 -48.25 -48.06 -48.06 -48.34 -47.07"
Et voici la regexp que j'ai pour la détecter : "(([\s]{1}[0-9\.-]+)+)".

Cela fonctionne correctement, mais ça ne me retourne que 2 groupes de capture. Le premier  contient toute la chaîne en entrée, le second ne contient que le dernier bloc de valeur " -47.07".

Je voudrais que le pattern puisse générer 10 groupes contenant les 10 valeurs. Seulement dans l'exemple ici c'est 10, mais ça peut varier.

Comment faire, via expression régulière pour capturer dynamiquement le bon nombre de groupe sans créer un pattern en dur avec la répétition du même motif 10 fois ?

 

Lien vers le commentaire
Partager sur d’autres sites

Oui ça fonctionnerait en effet, tout comme (encore plus simple) un bête stringsplit(" "). Mais l'inconvénient de ces 2 solutions est que cela implique de faire soi-même une boucle for. Non pas que c'est un problème, amis il me semble, à la lecture de cet article qu'on peut déjà gérer ça via la syntaxe regexp.

Lien vers le commentaire
Partager sur d’autres sites

Juste une remarque rapide en lisant la regex: me "-" est réservé donc tu dois l'échapper (\-). Je le rendrait aussi optionnel et toujours devant les chiffres.

[0-9\.-]+ devient \-?[0-9\.]+

Exemple (non vérifié):

(([\s]{1}\-?[0-9\.]+)+)

Attention [0-9\.]+ capture encore quelque chose comme 12.34.56

Il faudrait bien découper (en séparant les nombre entiers des décimaux)

[0-9]+\.[0-9]*|[0-9]+

 

Lien vers le commentaire
Partager sur d’autres sites

Il me semble que les groupes servent à faire une recherche de précision sur un ensemble large en se référant à un groupe détecté auparavant.

Du coup, c'est pour quel cadre ? Récupérer chaque "groupe" pour les stocker en variable ? Car pour ça, il y a déjà des fonctions dans les langages. preg_match_all() en PHP ou Matches()  en C# par exemple.

Lien vers le commentaire
Partager sur d’autres sites

L'objectif est en effet de récupérer chaque groupe afin de reconstruire un tableau de valeur décimales. Le langage, c'est du Java.

Pour le moment je n'utilise la regexp que pour sélectionner les lignes intéressantes dans mon flux ASCII d'entrée, ensuite je fais un split() sur les espaces, et un simple parseDouble sur les valeurs du tableau du split :

// Parse answer
Pattern p2 = Pattern.compile("(([\\s]?[0-9\\.-]+)+)");
String[] answerLines = res.split("\r\n");

int sliceCount = 839;
double[][] sliceMatrix = new double[84][10];
int rowMatrix = 0;

for(String line : answerLines) {
	if(!line.startsWith(" "))
		continue;
	
	Matcher m2 = p2.matcher(line);
	if(m2.matches()) {
		String[] values = m2.group(1).substring(1).split(" ");
		
		for(int aa = 0; aa < values.length; aa++) {
			sliceMatrix[rowMatrix][aa] = Double.parseDouble(values[aa]);
		}
		rowMatrix++;
	}
}

Ça fonctionne très bien évidement, c'est le B-A-BA. Seulement, à la lecture des différents tutoriaux présents sur le site que j'ai cité plus haut, j'ai cru comprendre qu'il y avait la possibilité d'arriver au même résultat directement via la syntaxe regexp, sans split derrière.

C'est donc cette méthode élégante que je cherche à comprendre et à utiliser. C'est de l'enrichissement de culture plus que du besoin, puisque j'ai déjà une solution fonctionnelle.

Lien vers le commentaire
Partager sur d’autres sites

Je pense que ton problème c'est le greedy matching

(([\s]-[\d\.]+)+?)

Je me suis permis d'enlever le - du groupe

remarque le ? après le +, cela permet d'avoir une limitation au plus petit pattern qui match. Sinon il prend le plus grand pattern qui est … toute la chaine et donc ne génère qu'un groupe. On passe alors du greedy au lazzy 

https://regex101.com/r/1RA98S/2

Edit: enfin… ca c'était pour répondre à ta regexp initiale

Car sinon le group spliting est juste via le pattern matc

-[\d\.]+

https://regex101.com/r/1RA98S/3

ou plus sexy -[\d]+(\.[\d]+)

https://regex101.com/r/1RA98S/4

Et le plus performant sera certainement un simple split sur les espaces sans regexp car attention, les regexp ca a l'air magique car ca peut tout faire en 1 seule instruction mais c'est une opération couteuse.

Edit2: histoire de décrasser mon java:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HelloWorld{
  public static void main(String args[]) {

      Matcher m = Pattern.compile("-[\\d]+(\\.[\\d]+)")
     .matcher( " -59.99 -46.54 -25.59 -25.09 -25.51 -48.25 -48.06 -48.06 -48.34 -47.07");
     while (m.find()) {
        System.out.println(m.group());
     }
  }
}

 

Lien vers le commentaire
Partager sur d’autres sites

Quelle version de java ?

car avec Java 8, il y a les streams ... ( mais j'ai un peu de mal avec l'énoncé au niveau de "10 groupes contenant les 10 valeurs", je ne sais pas si ça correspond à 100% )

 

exemple:

        String toto= " -59.99 -46.54 -25.59 -25.09 -25.51 -48.25 -48.06 -48.06 -48.34 -47.07";
        List<String> lst = Arrays.asList(toto.split(" ")).stream().map(p-> StringUtils.trim(p)).collect(Collectors.toList()) ;

tu peux rajouter un cast en Double si souhaite avoir une type nombre

Lien vers le commentaire
Partager sur d’autres sites

On 11/01/2019 at 15:03, Sheepux a écrit :

Passe ce WE sur le discord NXI je pourrai t'expliquer.

Merci beaucoup pour l'invitation :yes: mais tous ces outils de messagerie web audio/vidéo, c'est pas ma tasse de thé...

 

On 11/01/2019 at 15:37, Chocobidou a écrit :

car avec Java 8, il y a les streams ...

Oui en effet, j'utilise pas mal les streams sur les opérations de listes ou de tableaux, mais ça fait toujours intervenir le string.split(), et je souhaitais surtout apprendre l'utilisation de la regexp correcte.

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...