[Perl] extraction de chaine
Résolu/Fermé
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
-
5 juin 2007 à 11:38
nico3fr Messages postés 34 Date d'inscription jeudi 31 mai 2007 Statut Membre Dernière intervention 17 janvier 2008 - 6 juin 2007 à 22:01
nico3fr Messages postés 34 Date d'inscription jeudi 31 mai 2007 Statut Membre Dernière intervention 17 janvier 2008 - 6 juin 2007 à 22:01
A voir également:
- [Perl] extraction de chaine
- Chaine tnt gratuite sur mobile - Guide
- Plus de chaine tv - Guide
- Nouvelle chaîne tnt gratuite 2024 - Accueil - TV & Vidéo
- Chaine radio - Télécharger - Médias et Actualité
- Denon perl pro test - Accueil - Audio
9 réponses
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
5 juin 2007 à 20:46
5 juin 2007 à 20:46
A quoi servent les parentheses autour des variables $un et $deux (bon, c'est sur qu'elles servent, parce que si je les mets pas ca me retourne 1) ?
($un)= $var =~ /(?<=carac2=)(.*?)\s/;
Les parenthèses de la regex nous permet de faire une capture dans les variables spéciales $1,$2, etc
donc je pourrais écrire
$var =~ /(?<=carac2=)(.*?)\s/;
$un = $1;
En revanche j'ai choisi ($un) à cause de ma paresse.
Pourquoi $un entouré des parenthèses?
Parce que je fais la capture de la regex dans un contexte de liste sans avoir besoin de passer par les variables $1, etc...
Ca c'est un point essentiel en Perl. Si tu ne comprends pas ça alors c'est difficile d'aller plus loin.
L'affectation d'une liste dans un contexte scalaire retourne le nombre d'éléments qui sont affectés. En ce cas un seul
Si tu fait plusieurs captures et tu utilises seulement une variable en contexte de liste alors les autres captures seront perdues.
Voici un exemple en utilisant le contexte de liste et le contexte scalaire
1. Lire une liste dans un contexte scalaire - retourne les nombres d'éléments
2. lire une liste dans un contexte de liste - retourne les éléments, avec la remarque que des valeurs sont perdu si on n'utilise pas le même nombre de variables - un solution c'est d'utiliser directement un tableau ou un hash (qui va bien dans ton cas vu que tu as des couple cle=valeur)
Et ensuite deuxième question, c'est ce que signifie les ?<= avant les carac1 et carac2,
Il s'agit d'un test arrière positif. Donc pour capturer ce que j'ai besoin, je regarde en arrière pour voir si le motif correspond.
C'est très pratique quand on parse des gros fichier, puisque le test avant et/ou arrière, positif et/ou negatif, ne consomment pas de texte, ce qui peut rendre une regex plus performante.
Pareil pour le ? dans (.*?)
Ici il s'agit de la gourmandise du quantificateur *
Pour comprendre je vais te donner un exemple
Dans le 1er cas .* tu remarques que * avale toute les caractères compris entre le 1er c et le dernier c de notre chaine.
En bref * veut dire : prendre zéro caractères, un caractères ou n'importe combien tu peux.
Comme * il est gourmand alors il va prendre tout
Dans le 2ème cas .*? la capture s'arrête au 1er c rencontré.
*? veut dire : prend zéro caractères, un caractère, mais content toi avec le minimum.
On peut tirer la conclusion qu'un quantificateur minimal préfère la satisfaction à la gourmandise
Une autre situation ça sera: la récupération de la chaine entre l'avant dernier et le dernier c
En ce cas on va écrire comme ça
D'abord la regex va avaler tout grace à .* et ensuite il sera obliger de céder sous contrainte le 1er c rencontrer qui est le dernier dans la chaine.
Une fois que la regex a récupéré le dernier c va essayer d'avaler encore des caractères pour trouver un autre c, mais comme elle ne le trouve pas le .* de début va céder encore un caractère et ainsi de suite jusqu'à quand c.*c et satisfait
Bon, j'espère que tu as compris un peu :-))
($un)= $var =~ /(?<=carac2=)(.*?)\s/;
Les parenthèses de la regex nous permet de faire une capture dans les variables spéciales $1,$2, etc
donc je pourrais écrire
$var =~ /(?<=carac2=)(.*?)\s/;
$un = $1;
En revanche j'ai choisi ($un) à cause de ma paresse.
Pourquoi $un entouré des parenthèses?
Parce que je fais la capture de la regex dans un contexte de liste sans avoir besoin de passer par les variables $1, etc...
Ca c'est un point essentiel en Perl. Si tu ne comprends pas ça alors c'est difficile d'aller plus loin.
L'affectation d'une liste dans un contexte scalaire retourne le nombre d'éléments qui sont affectés. En ce cas un seul
Si tu fait plusieurs captures et tu utilises seulement une variable en contexte de liste alors les autres captures seront perdues.
Voici un exemple en utilisant le contexte de liste et le contexte scalaire
1. Lire une liste dans un contexte scalaire - retourne les nombres d'éléments
$ echo Perl pour plaisir | perl -ne '$nombre = ($un,$deux,$trois) = $_ =~ /(p)/gi;print "$nombre\n"' $ echo Perl pour plaisir | perl -ne '$nombre = () = $_ =~ /(p)/gi;print "$nombre\n"' 3 $ echo Perl pour plaisir | perl -ne '$nombre = @nombre = $_ =~ /(p)/gi;print "$nombre\n"' 3
2. lire une liste dans un contexte de liste - retourne les éléments, avec la remarque que des valeurs sont perdu si on n'utilise pas le même nombre de variables - un solution c'est d'utiliser directement un tableau ou un hash (qui va bien dans ton cas vu que tu as des couple cle=valeur)
$ echo Perl pour plaisir | perl -ne '($un) = $_ =~ /(p)/gi;print "$un $deux $trois\n"' P $ echo Perl pour plaisir | perl -ne '($un,$deux) = $_ =~ /(p)/gi;print "$un $deux $trois\n"' P p $ echo Perl pour plaisir | perl -ne '($un,$deux,$trois) = $_ =~ /(p)/gi;print "$un $deux $trois\n"' P p p $ echo Perl pour plaisir | perl -ne '@nombre = $_ =~ /(p)/gi;print "@nombre\n"' P p p
Et ensuite deuxième question, c'est ce que signifie les ?<= avant les carac1 et carac2,
Il s'agit d'un test arrière positif. Donc pour capturer ce que j'ai besoin, je regarde en arrière pour voir si le motif correspond.
C'est très pratique quand on parse des gros fichier, puisque le test avant et/ou arrière, positif et/ou negatif, ne consomment pas de texte, ce qui peut rendre une regex plus performante.
Pareil pour le ? dans (.*?)
Ici il s'agit de la gourmandise du quantificateur *
Pour comprendre je vais te donner un exemple
$ echo commentcamarche
commentcamarche
$ echo commentcamarche | perl -ne 'print $1,"\n" if /(c.*c)/'
commentcamarc
$ echo commentcamarche | perl -ne 'print $1,"\n" if /(c.*?c)/'
commentc
Dans le 1er cas .* tu remarques que * avale toute les caractères compris entre le 1er c et le dernier c de notre chaine.
En bref * veut dire : prendre zéro caractères, un caractères ou n'importe combien tu peux.
Comme * il est gourmand alors il va prendre tout
Dans le 2ème cas .*? la capture s'arrête au 1er c rencontré.
*? veut dire : prend zéro caractères, un caractère, mais content toi avec le minimum.
On peut tirer la conclusion qu'un quantificateur minimal préfère la satisfaction à la gourmandise
Une autre situation ça sera: la récupération de la chaine entre l'avant dernier et le dernier c
En ce cas on va écrire comme ça
$ echo commentcamarche | perl -ne 'print $1,"\n" if /.*(c.*c)/' camarc
D'abord la regex va avaler tout grace à .* et ensuite il sera obliger de céder sous contrainte le 1er c rencontrer qui est le dernier dans la chaine.
Une fois que la regex a récupéré le dernier c va essayer d'avaler encore des caractères pour trouver un autre c, mais comme elle ne le trouve pas le .* de début va céder encore un caractère et ainsi de suite jusqu'à quand c.*c et satisfait
Bon, j'espère que tu as compris un peu :-))
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
5 juin 2007 à 14:38
5 juin 2007 à 14:38
Salut,
je n'ai pas testé
1.
lami20j
je n'ai pas testé
1.
($un)= $var =~ /(?<=carac2=)(.*?)\s/;2.
($deux) = $var =~ /(?<=carac3=)(.{4})/;--
lami20j
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
5
5 juin 2007 à 15:32
5 juin 2007 à 15:32
Super !
Ca marche nikel :)
J'aurais juste une ou deux petites questions, histoire que j'apprenne un peu.
A quoi servent les parentheses autour des variables $un et $deux (bon, c'est sur qu'elles servent, parce que si je les mets pas ca me retourne 1) ? Mais je voulais savoir comment s'était interprété, savoir quand en mettre quoi ;)
Et ensuite deuxieme question, c'est ce que signifie les ?<= avant les carac1 et carac2, je suppose que c'est pour la recherche des mots, mais je voudrais bien un peu plus de details sur la syntaxe.
Pareil pour le ? dans (.*?)
Merci
Ca marche nikel :)
J'aurais juste une ou deux petites questions, histoire que j'apprenne un peu.
A quoi servent les parentheses autour des variables $un et $deux (bon, c'est sur qu'elles servent, parce que si je les mets pas ca me retourne 1) ? Mais je voulais savoir comment s'était interprété, savoir quand en mettre quoi ;)
Et ensuite deuxieme question, c'est ce que signifie les ?<= avant les carac1 et carac2, je suppose que c'est pour la recherche des mots, mais je voudrais bien un peu plus de details sur la syntaxe.
Pareil pour le ? dans (.*?)
Merci
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
5
6 juin 2007 à 14:22
6 juin 2007 à 14:22
Merci beaucoup pour tes explications.
Ca repond en plus a une nouvelle question que je me posais pour capturer un ensemble de choix dans une variable et les stocker dans un tableau :)
Par exemple pour faire une selection de choix d'execution :
Ou bien y'a peut etre une methode plus simple qui existe (sachant que je n'ai pas acces a l'instruction switch)
Merci :)
Ca repond en plus a une nouvelle question que je me posais pour capturer un ensemble de choix dans une variable et les stocker dans un tableau :)
Par exemple pour faire une selection de choix d'execution :
print("Faites vos choix :\n"); print("Exemple : 1 4\n"); print("1 - afficher toto\n"); print("2 - afficher tata\n"); print("3 - afficher titi\n"); print("4 - afficher tutu\n"); @choix =<stdin>=~ /\d/g; $i =0; while (@choix[$i] =~ /\d/) { if (@choix[$i] == "1") { print("toto\n"); $i++; } elsif (@choix[$i] == "2") { print("tata\n"); $i++; } elsif (@choix[$i] == "3") { print("titi\n"); $i++; } elsif (@choix[$i] == "4") { print("tutu\n"); $i++; } else { print("@choix[$i] n'est pas un choix correct\n"); $i++; } }
Ou bien y'a peut etre une methode plus simple qui existe (sachant que je n'ai pas acces a l'instruction switch)
Merci :)
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
5
6 juin 2007 à 17:13
6 juin 2007 à 17:13
Tiens j'aurais une autre question :D
Admettons que je remplace mon while par :
(nb_choix) etant le nombre de choix total présent
Comment je pourrais rajouter un check pour que l'utilisateur ne rentre pas 2 fois la meme commande?
Admettons que je remplace mon while par :
foreach $var (@choix) { if ($var <=0 || $var > $nb_choix) { print("commande pas valide\n"); } else { print("commande lancé : $var"); } }
(nb_choix) etant le nombre de choix total présent
Comment je pourrais rajouter un check pour que l'utilisateur ne rentre pas 2 fois la meme commande?
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
6 juin 2007 à 18:32
6 juin 2007 à 18:32
Je viens d'entrer à la maison.
Je vais me pencher sur tes questions un peu plus tard :-))
En revanche j'ai aussi des questions à te poser.
Pour ton message N°4, tu veux écrire un menu qui s'affichera toujours jusqu'à quand l'utilisateur tape quitter (c'est un exemple) ?
Pour ton message N°5
Comment je pourrais rajouter un check pour que l'utilisateur ne rentre pas 2 fois la même commande?
Tu ne pourra jamais faire ça, à moins que tu reste derrière lui avec une matraque :-)))))
En revanche tu peux gérer ces erreurs. C'est ça que tu veux?
En ce qui concerne while et foreach il faut bien comprendre leur rôle
while c'est une boucle qui s'exécute tant que la condition soit vraie
foreach c'est une boucle sur chaque élément d'une liste
A plus tard :-))
Je vais me pencher sur tes questions un peu plus tard :-))
En revanche j'ai aussi des questions à te poser.
Pour ton message N°4, tu veux écrire un menu qui s'affichera toujours jusqu'à quand l'utilisateur tape quitter (c'est un exemple) ?
Pour ton message N°5
Comment je pourrais rajouter un check pour que l'utilisateur ne rentre pas 2 fois la même commande?
Tu ne pourra jamais faire ça, à moins que tu reste derrière lui avec une matraque :-)))))
En revanche tu peux gérer ces erreurs. C'est ça que tu veux?
En ce qui concerne while et foreach il faut bien comprendre leur rôle
while c'est une boucle qui s'exécute tant que la condition soit vraie
foreach c'est une boucle sur chaque élément d'une liste
A plus tard :-))
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
5
6 juin 2007 à 19:30
6 juin 2007 à 19:30
Pour ma question 4, idealement, j'aimerais un menu dans lequel l'utilisateur pourrait choisir 1, plusieurs ou tous les choix proposés.
Actuellement, je réccupère l'ensemble des choix decimaux de l'utilisateur :
et avec le foreach, je traite l'ensemble de ses choix.
Par contre, dans les commandes que j'execute, je ne peux pas executer 2 fois la meme. D'ou ma question dans le message 5.
Sais tu ou je pourrais acheter une bonne matraque?
Bon... d'accord, d'accord, je veux bien plutot essayer de traiter les erreurs de l'utilisateur :)
En tout cas, merci beaucoup pour ton aide.
Actuellement, je réccupère l'ensemble des choix decimaux de l'utilisateur :
@choix =<stdin>=~ /\d/g;
et avec le foreach, je traite l'ensemble de ses choix.
Par contre, dans les commandes que j'execute, je ne peux pas executer 2 fois la meme. D'ou ma question dans le message 5.
Sais tu ou je pourrais acheter une bonne matraque?
Bon... d'accord, d'accord, je veux bien plutot essayer de traiter les erreurs de l'utilisateur :)
En tout cas, merci beaucoup pour ton aide.
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
6 juin 2007 à 20:50
6 juin 2007 à 20:50
Bon, je te donne un exemple pour l'étudier, ensuite si tu pense à concevoir quelque chose il faut me dire ce que tu veux faire.
En travaillant comme ça sur de bout des codes n'est pas très sympa :-))
Si tu veux tout simplement apprendre alors pas de problèmes, mais il faut lire un peu la documentation :-))
Script Exemple
Résultat
lami20j
En travaillant comme ça sur de bout des codes n'est pas très sympa :-))
Si tu veux tout simplement apprendre alors pas de problèmes, mais il faut lire un peu la documentation :-))
Script Exemple
#!/usr/bin/perl use strict;use warnings; print "*" x 16 ,"\n"; print "* MENU *\n"; print "*" x 16 ,"\n"; print <<'FIN'; 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu FIN print "Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : "; chomp (my $choix = <STDIN>); my @choix = split " ",$choix; my %h = ( 1 => 'toto', 2 => 'tata', 3 => 'titi', 4 => 'tutu', ); SWITCH: { @choix == 0 and die "Vous devez faire un choix\n"; die "Options inconnue\n" if grep { /\D/ } @choix ; @choix == 1 && do { print $h{$choix[0]},"\n" ;last SWITCH; }; @choix > 1 && do { local $"="\n";print "@h{@choix}\n";last SWITCH; }; } __END__
Résultat
lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : 1 toto lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : 1 3 toto titi lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : 1 2 3 4 toto tata titi tutu lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : 1 4 toto tutu lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : Vous devez faire un choix lami20j@debian:~/trash$ perl ccm.pl **************** * MENU * **************** 1 - Afficher toto 2 - Afficher tata 3 - Afficher titi 4 - Afficher tutu Choisissez une ou plusieurs options séparéés par un espace [ ex : 1 3 4 ] : 1 2 a Options inconnue lami20j@debian:~/trash$--
lami20j
nico3fr
Messages postés
34
Date d'inscription
jeudi 31 mai 2007
Statut
Membre
Dernière intervention
17 janvier 2008
5
6 juin 2007 à 22:01
6 juin 2007 à 22:01
Je regarderais ca + en détails demain.
Mais oui, je lis pas mal de docs ces derniers jours, j'ai commencé le perl y'a 3 jours, donc j'apprends petit a petit ;)
Je prend des bouts de code par ci par la que je retravaille.
Mais bon, parfois je bloque sur des trucs "a la con" j'ai envie de dire... Et trouver des docs qui expliquent ces cas en question c'est pas toujours facile facile.
Enfin bref, j'arrive bientot sur la fin de mon script. Promis je te montrerais l'ensemble à la fin.
Mais oui, je lis pas mal de docs ces derniers jours, j'ai commencé le perl y'a 3 jours, donc j'apprends petit a petit ;)
Je prend des bouts de code par ci par la que je retravaille.
Mais bon, parfois je bloque sur des trucs "a la con" j'ai envie de dire... Et trouver des docs qui expliquent ces cas en question c'est pas toujours facile facile.
Enfin bref, j'arrive bientot sur la fin de mon script. Promis je te montrerais l'ensemble à la fin.