Les fonctions spécifiques.

split().

Cette fonction a déjà été évoquée brièvement. Nous y revenons car elle présente un certain nombre de particularités qui la lient aux expresions régulières.
Les paramètres de l'opérateur split() sont une expressionrégulière et une chaîne de caractères. Les portions de la chaîne qui ne correspondent pas à l'expression régulière sont retournées séquentiellement comme une liste de valeurs.
La coupure entre les divers éléments de la liste étant gérée par l'expression régulière.

Programme fns1.pl Exécution sur l'écran
$cible = "Un Deux Trois Quatre";
print "$cible\n";
@table = split(/ /g,$cible);
print "$table[0]\n";
print "$table[1]\n";
print "$table[2]\n";
print "$table[3]\n";
print "$table[4]\n";
print "$table[5]\n";
    
c:\progs> perl fns1.plent
Un Deux Trois Quatre
Un
Deux
Trois
Quatre
c:\progs>
    

Dans le cas le plus simple, l'expression régulière se réduit à un unique espace.
Rappelons ces exemples qui ont déjà été vus dans le chapitre sur les listes.

Programme list33.pl Exécution sur l'écran
$l = "chris::120:50:C. Aperghis:/home/chris:/bin/csh";
($nom,$pass,$uid,$gid,$gcos,$rep,$sh) = split(/:/,$l);
print "nom : $nom";
print " mot de passe : $pass\n";
print "uid : $uid";
print " gid : $gid\n";
print "gcos : $gcos";
print " repertoire : $rep\n";
print "shell : $shell\n";
    
c:\progs> perl list33.plent
nom : chris
mot de passe :
uid : 120
gid : 50
gcos : C. Aperghis
repertoire : /home/chris
shell : /bin/csh
c:\progs>
    
Programme list34.pl Exécution sur l'écran
$l = "chris::120:50:C. Aperghis:/home/chris:/bin/csh";
@liste = split(/:/,$l);
for ($i=0;$i<=$#liste;$i++) {
  print ("$liste[$i]\n");
}
    
c:\progs> perl list34.plent
chris

120
50
C. Aperghis
/home/chris
/bin/csh
c:\progs>
    

Et le petit problème consistant à lire une chaîne de caractères qui comporte exclusivement des 1 et des 0 et dans laquelle on désire compter le nombre de 1 et le nombre de 0.

Programme list35.pl Exécution sur l'écran
$l = "Hello.";
@liste = split(//,$l);
for ($i=0;$i<=$#liste;$i++) {
  print ("$liste[$i]\n");
}
    
c:\progs> perl list35.plent 
H e l l o . c:\progs>
Programme list36.pl Exécution sur l'écran
$ligne = <stdin>;
$z = split(/0/,$ligne) -1;
$u = split(/1/,$ligne) -1;
print ("La chaîne $ligne,\n");
print ("contient\n");
print ("$z fois le chiffre 0.\n");
print ("$u fois le chiffre 1.\n");
    
c:\progs> perl list36.plent
10101011001011111000101011010ent
La chaîne 10101011001011111000101011010,
contient
13 fois le chiffre 0.
16 fois le chiffre 1.
c:\progs>
    

Il est important que la chaîne soit lue afin de se terminer par un caractère qui ne soit ni 1 ni 0, dans ce cas, le caractère \n.
Pour le reste, il faut faire appel aux vieux souvenirs du primaire lorsqu'on comptait les piquets et les intervalles.

Voyons maintenant un exercice un peu plus évolué. Dans un certain nombre de fichiers passés par l'intermédiaire de la liste @ARGV, on désire compter le nombre d'occurences d'un mot donné.
Le critère de recherche sera lu sur <STDIN>

c:\progs> type compte.plent
#!usr/bin/perl
@ARGV =("Poeme.txt","Darwin.txt");
$nf = @ARGV;
print "Quel est le mot à rechercher ? ";
chop($critere = <stdin>);
print ("On recherche le mot : $critere.\n\n");
$total = $compt = 0;
$fichier = $ARGV[0];
while ($ligne =<>) {
  chop ($ligne);
  @mots = split (/ /,$ligne);
  $w = 0;
  while ($w <= @mots) {
    if ($mots[$w] eq $critere) {
      $compt += 1;
    }
  $w++;
  }
  if (eof) {
    print ("Dans le fichier $fichier ");
    print ("Il y a $compt");
    print ("occurences du mot $critere\n\n");
    $total += $compt;
    $compt = 0;
    $fichier = $ARGV[0];
  }
}
print ("Le mombre total d'occurences pour ");
print ("les $nf fichiers est de $total\n");
c:\progs> perl compte.plent
Quel est le mot à rechercher ? laent
On recherche le mot : la.

Dans le fichier Poeme.txt Il y a 2 occurences du mot la

Dans le fichier Darwin.txt Il y a 61 occurences du mot la

Le mombre total d'occurences pour les 2 fichiers est de 63
c:\progs>
  

Quelques commentaires sur le programme qui vient d'être présenté.

@ARGV = ("Poeme.txt","Darwin.txt"); Affectation des noms de fichiers à la liste @ARGV. L'accés aux fichiers sera séquentiel,tout d'abord Poeme.txt puis Darwin.txt.
$nf = @ARGV; Le scalaire $nf contient le nombre de fichiers à lire (nombre d'éléments de la liste@ARGV.
print "Quel est le mot à rechercher ? ";
chop($mot = <stdin>);
print ("On recherche le mot : $critere.\n\n");
$total = $compt = 0;
Aucune difficulté.
On initialise les deux compteurs pour le décompte fichier par fichier et le décompte total.
$fichier = $ARGV[0]; Afin de pouvoir identifier le fichier au moment de l'impression, on récupère son nom.
Le fichier en cours de traitement est le premier de la liste ($ARGV[0]).
while ($ligne =<>) {
chop ($ligne);
}
Opérateur diamand et boucle sur l'ensemble des lignes des fichiers dont le nom se trouve dans @ARGV.
@mots = split (/ /,$ligne);
$w = 0;
while ($w <= @mots) {
if ($mots[$w] eq $critere) {
$compt += 1;
}
$w++;
}
Découpage de la chaîne pour créer une liste dont chaque élément représente un mot. Puis parcours de la liste et décompte.
if (eof) {
print ("Dans le fichier $fichier ");
print ("Il y a $compt");
print ("occurences du mot $critere\n\n");
$total += $compt;
$compt = 0;
$fichier = $ARGV[0];
}
La fonction eof permet de tester le passage d'un fichier de la liste à l'autre. Le fichier qui vient d'être traité est alors retiré de la liste @ARGV. Le premier élément de cette liste est ainsi à nouveau le fichier en cours de traitement.

join().

C'est l'opérateur dual de l'opérateur split qui a lui aussi été présenté dans le chapitre sur les listes. Il permet de réunir les éléments d'une liste en une chaîne de caractères. Un caractère passé en paramètre fera le joint entre les divers éléments.

$ch = join("-",@liste);
Programme list37.pl sur l'écran Exécution sur l'écran
@liste = ("Programmer","en","Perl");
for ($i=0;$i<=$#liste;$i++) {
  print ("$liste[$i]\n");
}
$c1 = join(" ",@liste);
print ("$c1\n");
$c2 = join(" - ",@liste);
print ("$c2\n");
    
c:\progs> perl list37.plent
Programmer
en
Perl
Programmer en Perl
Programmer - en - Perl
c:\progs>
    

La fonction splice() .

La fonction splice permet de modifier des éléments d'une liste. Il y a de multiples manières d'utiliser cette fonction. Sa forme générale est :

@retour = splice (@variable, $decalage, $longueur, @nouvelle_liste);
@variable nom de la variable contenant la liste.
$decalage> nombre d'éléments à sauter avant de commencer l'opération.
$longueur Si cette valeur est supérieure à zéro, @retour contiendra la liste des éléments remplacés.
Programme fns2.pl sur l'écran Exécution sur l'écran
#!/usr/bin/perl
@liste = ("Nbs","un","deux","trois","quatre","cinq");
@valeurs =("1","2","3","4","5");
@retour = splice (@liste,1,2,@valeurs);
print ("Liste des élémentsremplacés :\n@retour\n");
print ("\nNouvelleliste d'éléments:\n@liste\n");
    
c:\progs> perl fns2.plent
Liste d'éléments qui ont été remplacés :
un deux

Nouvelle liste d'éléments :
Nbs 1 2 3 4 5 trois quatre cinq
c:\progs>
    

Dans la liste @liste, on remplace 2 éléments (troisième paramètre) àpartir du second (on en saute 1, second paramètre) par les éléments de la liste @valeur. Les éléments de la liste @liste quisont concernés se retrouvent dans la liste @retour.

Voici un poème de Ronsard qui va nous permettre de mettre en application un certain nombre de fonctions de traitement des chaînes de caractères.

Terre,ouvre-moi ton sein, et me laisse reprendre
Mon tresor, que ta parque a cache dessous toi;
Ou bien, si tu ne peux, o terre, cache moi
Sous meme sepulture, avec sa belle cendre.

Le trait qui la tua devait faire descendre
Mon corps aupres du sien pour finir mon emoi;
Aussi bien, vu le mal qu'en sa mort je recoit,
Je ne saurais plus vivre, et me fache d'attendre.

Quand ses yeux m'eclairaient, et qu'en terre j'avais
Le bonheur de les voir, a l'heure je vivais,
Ayant de leurs rayons mon ame gouvernee.

Maintenant je suis mort : la Mort qui s'en alla
Loger dedans ses yeux, en parlant m'appela,
Et me fit de ses pieds accomplir ma journee.

Ronsard, (Sur la mort de Marie, 1578).

Dans ce texte nous désirons isoler tous les mots dont la longueur est comprise entre 3 et 5.

Programme fns3.pl Exécution sur l'écran
#!/usr/bin/perl
@ARGV =("Poeme.txt");
>while ($ligne = <>) {
  @mots = split (/\s+/,$ligne);
  $i = 0;
  while (defined ($mots[$i])) {
    $word[$i] = ~s/[,.;:]$///;
    if ((length($mots[$i])>5)or(length($mots[$i])<=2)) {
      splice (@mots,$i,1);
    } else { 
      $i++;
    }
  }
$ligne = join (" ",@mots);
print ("$ligne\n");
}
    
c:\progs> perl fns3.plent
ton sein,
Mon que cache toi;
bien, peux, cache moi
Sous meme avec belle

trait qui tua faire
Mon corps sien pour finir mon emoi;
Aussi bien, mal qu'en mort
plus fache

Quand ses yeux qu'en terre
les voir,
Ayant leurs mon ame

suis mort Mort qui s'en alla
Loger ses yeux,
fit ses pieds
c:\progs>
    

L'opérateur map().

L'opérateur map va permettre de considérer tour à tour chaque élément d'une liste comme opérande d'une expression donnée.

@liste_de_resultats = map(expression,@liste);
Programme fns4.pl Exécution sur l'écran
#!/usr/bin/perl
@liste =("1","2","3","4","5");
@resultat = map($_*$_,@liste);
print ("Liste d'origine :\n");
print ("@liste\n");
print ("\nListe aprés calcul :\n");
print ("@resultat\n");
    
c:\progs> perl fns4.plent
Liste d'origine :
1 2 3 4 5

Liste aprés calcul :
1 4 9 16 25
c:\progs>
    

La fonction index().

Cette fonction permet de déterminer si une sous chaîne est ou n'est pas présente dans une chaîne donnée, et à quel emplacement elle se trouve.

>$x = index ($chaine,$sschaine)

Si la chaîne débute par la sous chaîne, la réponse est 0.
Si la chaîne débute par un caractère suivi de la sous chaîne, la réponse est 1.
Si la chaîne débute par deux caractère suivi de la sous chaîne, la réponse est 2.
etc ...
Si la sous chaîne est absente de la chaîne de référence, la réponse est -1.
Si plusieurs occurences de la sous chaîne sont présentes dans la chaîne de référence, seule celle située la plus à gauche sera considérée.

Programme fns5.pl Exécution sur l'écran
#!/usr/bin/perl
$x = index ("Bonjour","n");
print "Valeur dex : $x\n";
$y = "beau";
$x = index ("Il fait beau",$y);
print "Valeur de x : $x\n";
@z = ("lundi","mardi");
$y = "mardi";
$x = index ($z,$y);
$x = index (join ( " ",@z),$y);
print "Valeur de x : $x\n";
@z =("lundi","mardi");
$y = "jeudi";
$x = index($z,$y);
$x = index ( join ( " ",@z),$y);
print "Valeur dex : $x\n";
    
c:\progs> perl fns5.plent
Valeur de x : 2
Valeur de x : 8
Valeur de x : 6
Valeur de x : -1
c:\progs>
    

Autre exemple d'utilisation de la fonction index().
Lire le fichier "poeme.txt" ligne par ligne et compter pour chacune d'elle le nombre d'ocurences d'un modèle donné.

c:\progs> type fns6.plent
#!usr/bin/perl
@ARGV =("poeme.txt");
# Modèle recherche, la lettre l en minuscule.
$c = "l";
$nl =$e= $n = 0;
$ligne = <>;
while ($ligne ne "") {
  $nl++;
while (1) { $e = index($ligne, $c, $e); last if ($e == -1); $n++; $e++; } print ("Ligne $nl, la chaîne $c aété trouvée $n fois.\n") if($n != 0); print("Ligne $nl, lachaîne $c n'est pas présente.\n") if ($n ==0); $ligne = <>; $e = 0; $n = 0; c:\progs> perl xxxx.plent Ligne 1, la chaîne 'l' a été trouvée 1 fois. Ligne 2, la chaîne l n'est pas présente. Ligne 3, la chaîne l n'est pas présente. Ligne 4, la chaîne 'l' a été trouvée 3 fois. Ligne 5, la chaîne l n'est pas présente. Ligne 6, la chaîne 'l' a été trouvée 1 fois. Ligne 7, la chaîne l n'est pas présente. Ligne 8, la chaîne 'l' a été trouvée 2 fois. Ligne 9, la chaîne 'l' a été trouvée 1 fois. Ligne 10, la chaîne l n'est pas présente. Ligne 11, la chaîne 'l' a été trouvée 1 fois. Ligne 12, la chaîne 'l' a été trouvée 2 fois. Ligne 13, la chaîne 'l' a été trouvée 1 fois. Ligne 14, la chaîne l n'est pas présente. Ligne 15, la chaîne 'l' a été trouvée 3 fois. Ligne 16, la chaîne 'l' a été trouvée 2 fois. Ligne 17, la chaîne 'l' a été trouvée 1 fois. c:\progs>

La fonction length().

Cette fonction permet de connaitre la longueur d'une chaîne.

$x = length ($chaîne);

Un exemple d'utilisation de la fonction length().
Lire le fichier "poeme.txt";
Compter le nombre de mots, le nombre total de caractères et en déduire la longueur moyenne des mots du poème.

c:\progs> type fns7.plent
#!usr/bin/perl
@ARGV =("Poeme.txt");
$nbmots = 0;
$nbcar = 0;
while ($ligne = <>) {
  @mots = split(/\s+/,$ligne);
  foreach $mot (@mots) {
    next if ($mot =~/^d+\.?\d+$/);
    $mot =~s/[,.;:]$//;
$nbmots ++; $nbcar += length($mot); } } print ("Nombre total de mots :$nbmots\n"); print ("Nombre total de caractères :$nbcar\n"); $moyenne = $nbcar / $nbmots; print ("Longueur moyenne d'un mot :$moyenne\n"); c:\progs> perl fns7.plent Nombre total de mots : 120 Nombre total de caractères : 503 Longueur moyenne d'un mot : 4.19166666666667 c:\progs>

La fonction tr().

Cette fonction est identique à celle de Unix.

$x = tr/recherche/remplacement/;

Elle va balayer la chaîne decaractères cible qui lui est spécifiée par l'intermédiaire de l'opérateur =~ ou celle contenue dans la variable d'entrée standard $_ si aucune cible n'est explicitement spécifiée
Elle rremplace tous les caractères de la liste 'recherche' par le caractère correspondant de la liste 'remplacement'. En retour, elle renvoie le nombre de caractères concernés par l'opération.
Par exemple, compter le nombre de signes de ponctuation et le nombre d'espaces présents dans le poème.

c:\progs> type fns8.plent
#!usr/bin/perl
@ARGV =("Poeme.txt");
while ($ligne = <>) {
  chomp ($ligne);
  $total_caracteres +=length($ligne);
  $_ = $ligne;
  $ponctuation += tr/,:;./,:;./;
  $espaces +=tr/ / /;
}
print ("Nombre total de caracteres : $total_caracteres\n");
print ("Nombre de signes de ponctuation : $ponctuation\n");
print ("Nombre d'espaces : $espaces\n");
c:\progs> perl fns8.plent
Nombre total de caracteres : 631
Nombre de signes de ponctuation : 22
Nombre d'espaces : 106
c:\progs>
  

L'astuce consiste a remplacer chaque caractère par lui même et a compter le nombre de remplacements effectués.

Extraction de chaînes.

La fonction substr() permet d'extraire une sous chaîne d'une chaîne donnée.
La sous chaîne est repérée par son emplacement et sa longueur dans la chaîne de référence.

$x = substr($chaîne,$debut,$longueur);

La valeur de la position de début répond aux critères définis pour la fonction index ().
La longueur indique le nombre de caractères à extraire à partir de cet emplacement.
Si le second paramètre dépasse la longueur résiduelle ou si il est tout simplement absent, la totalité de la fin de la chaîne sera extraite.

Programme fns9.pl Exécution sur l'écran
#!/usr/bin/perl
$x = "0123456789";
$debut = 3;
$longueur = 5;
$x =substr($chaîne,$debut,$longueur);
print "Valeur de x : $x\n";
    
c:\progs> perl fns9.plent
Valeur de x 34567
c:\progs>
    
Programme fns9bis.pl Exécution sur l'écran
#!/usr/bin/perl
$x = "0123456789";
$debut = 3;
$longueur = 1000;
$x =substr($chaîne,$debut,$longueur);
print "Valeur de x : $x\n";
    
c:\progs> perl fns9bis.plent
Valeur de x 3456789
c:\progs>
Programme fns9ter.pl Exécution sur l'écran
#!/usr/bin/perl
$x = "0123456789";
$debut = 3;
$x = substr($chaîne,$debut);
print "Valeur de x : $x\n";
    
c:\progs> perl fns9ter.plent
Valeur de x 3456789
c:\progs>
    
Programme fns10.pl Exécution sur l'écran
#!/usr/bin/perl
$exp = 0;
while ($e< 10) {
  print "10 ^ $exp est egal a ";
  $p = substr("10000000000",0,(++$e));
  print "$p\n";
}
    
c:\progs> perl fns10.plent
10 ^ 0 est egal a 1
10 ^ 1 est egal a 10
10 ^ 2 est egal a 100
10 ^ 3 est egal a 1000
10 ^ 4 est egal a 10000
10 ^ 5 est egal a 100000
10 ^ 6 est egal a 1000000
10 ^ 7 est egal a 10000000
10 ^ 8 est egal a 100000000
10 ^ 9 est egal a 1000000000
c:\progs>
    

De manière assez surprenante, la fonction substr() peut apparaitre à gauche d'une affectation. Dans ce cas, on procède a la s ubstitution de la sous chaîne en question par le contenu de la partie droite de l'affectation.

Programme fns11.pl Exécution sur l'écran
#!/usr/bin/perl
$x = "0123456789";
$debut = 6;
$longueur = 2;
substr($chaîne,$debut)= " six sept ;
print "Valeur de x : $x\n";
    
c:\progs> perl fns11.plent 
Valeur de x 012345 six sept 89
c:\progs>
    

La fonction grep().

Il s'agit ici aussi d'une fonction en provenance du monde Unix.

grep(Expression, @liste);

Elle va récupérer chacun des éléments de la liste dans la variable $_.
La variable standard sera alors évaluée en fonction de l'expression, et une nouvelle liste sera alors construite.

Programme fns11.pl Exécution sur l'écran
#!/usr/bin/perl;
@chiffres = (0,1,2,3,4,5,6,7,8,9);
@impairs = grep($_ % 2,@chiffres);
print join(", ",@impairs),"\n";
    
c:\progs> perl fns11.plent
1, 3, 5, 7, 9
c:\progs>
    

Les variables prédéfinies.

Nous avons souvent évoqué la notion de variable prédéfinie. Ce sont des variables qui sont automatiquement positionnées par l'interpréteur afin de fixer un certain nombre de paramètres ou de renvoyer des informations.
En voici quelques unes.

Variable Utilisation
$_ Variable scalaire standard.
@_ Variable liste standard.
$& chaîne qui couvre le modèle dans une expression régulière.
$` Couvre toute la partie de la chaîne qui précède le modèle.
$' Couvre toute la partie de la chaîne qui suit le modèle.
$n Numéro de lavariable mémorisée dans l'expression régulière.
$~ Variable de définition de format.
$| Variable contrôlant la bufférisation des données.
$@ Message d'erreur retourné par l'appel de eval.
$] Variable contenant le numéro de version.
$/ Variable contenant le séparateur standard de fin de ligne en entrée.
$\ Variable contenant le séparateur standard de fin de ligne en sortie.
$, Séquence de caractères imprimée entre chaque élément d'un print.
$" Séparateur d'éléments d'une liste dans une impression globale.
$# Format par défaut pourl'impression d'un flotant.
$? Code d'erreur du système.
$. Numéro de ligne courante du fichier en lecture.
$[ Premier indice d'une liste.
$; Pour travailler sur des hashs à plus d'une dimension.

Comme il n'est pas toujours évident de se souvenir de tous ces noms barbares. Il existe pour en simplifier l'utilisation une bibliothèque (English) qui permet d'utiliser des noms symboliques.

Programme eng.pl Exécution sur l'écran
#!/usr/bin/perl;
use English;
print ("$PERL_VERSION")
    
c:\progs> perl eng.plent
5.004
c:\progs>
    
Variable Nom symbolique
$_ $ARG
$0
$PROGRAM_NAME
$] $PERL_VERSION
$@ $EVAL_ERROR
$. $INPUT_LINE_NUMBER ou $NR
$: $FORMAT_LINE_BREAK_CHARACTERS
$" $LIST_SEPARATOR
$~ $FORMAT_NAME
$| $OUTPUT_AUTOFLUSH
$& $MATCH
$` $PREMATCH
$'
$POSTMATCH
$/ $INPUT_RECORD_SEPARATOR ou $RS
$\ $OUTPUT_RECORD_SEPARATOR ou $ORS
$, $OUTPUT_FIELD_SEPARATOR ou $OFS

Utilisaton des variables prédéfinies.

Voici un exemple de l'utilisation de la variable $@ (message d'erreur retourné par un eval) pour verifier avant un appel de fonction que cette dernière existe bien. Nous verrons ultérieurement en detail le fonctionnement de "eval". Dans un premier temps, nous allons l'utiliser pour evaluer, en tant que programme, la valeur d'une chaîne de caractères qui lui est passée en paramètre.

Programme eval.pl Exécution sur l'écran
#!/usr/bin/perl;
eval('print "Bonjour\n";);
    
c:\progs> perl eval.plent
Bonjour
c:\progs>
    
Programme evalbis.pl Exécution sur l'écran
#!/usr/bin/perl;
open (POEME, "Poeme.txt");
eval ("\$debut = tell(POEME);");
print ("La fonction tell existe\n")if ($@ eq "");
print ("La fonction tell n'existe pas\n")if ($@ ne "");
    
c:\progs> perlevalbis.plent
La fonction tell existe
c:\progs>
    
Programme evalter.pl Exécution sur l'écran
#!/usr/bin/perl;
open (POEME, "Poeme.txt");
eval ("\$debut = talk(POEME);");
print ("La fonction talk existe\n") if ($@ eq "");
print ("La fonction talk n\'existe pas\n") if ($@ ne "");
    
c:\progs> perl evalter.plent
La fonction talk n'existe pas
c:\progs>
    

Explications :
On demande à appliquer la fonction sur un fichier.
Si tout s'est bien déroulé (fonction tell), aucune erreur n'aété générée et la variable $@ contient la valeur undef.
Dans le cas contraire (fonction talk) il y a eu génération d'une erreur et la variable $@ n'est pas vide.

Précédent
Suivant