site de Fabien Torre, université de Lille


Notes de cours sur le langage Perl

Introduction à la programmation en Perl pour le traitement automatique des textes : syntaxe générale, gestion des fichiers et expressions régulières.

Dans ce cours, nous passons en revue les éléments syntaxiques du langage Perl en parallèle avec le langage de description vu en cours d'algorithmique (variables, types, structures de contrôle, procédures et fonctions, etc.). En particulier quand Perl propose plusieurs syntaxes à une même fin, nous choisissons systématiquement la plus rigoureuse, la moins ambigüe, bref, la plus proche du cours d'algorithmique.

Puis nous nous intéressons à l'utilisation de Perl pour le traitements des textes, structurés ou non (lecture/écriture de fichiers, opérations sur les chaînes de caractères, expressions régulières, production de code HTML ou du code LaTeX, etc.).

Le détail des fonctions évoquées ici peut être obtenu à l'aide de la commande perldoc -f.

Instructions, expressions, variables et types Perl

Programmes, blocs d'instructions et instructions

Un programme Perl débute par les lignes suivantes :

#!/usr/bin/perl -w
use strict;
use utf8;

binmode(STDOUT,":utf8");

# puis des procédures et fonctions

# puis des appels aux procédures et fonctions

Commentaires sur ce premier code perl :

  • La première ligne précise où se trouve l'interpréteur perl qui va traiter la suite du programme (le chemin indiqué ici est valable sur les systèmes Linux, le fichier pourra être rendu exécutable et appelé dans un terminal). L'option -w demande à perl de signaler les éventuels warnings.
  • La deuxième ligne stipule que nous utilisons perl en mode strict, ce qui oblige par exemple à déclarer préalablement les variables utilisées.
  • Les deux lignes suivantes permettent de travailler en utf8 : dans le fichier perl et sur la sortie standard.
  • Notons également le caractère # qui permet d'introduire un commentaire que Perl ignorera.

En Perl, les blocs d'instructions sont délimités par des accolades  { représente un Début de bloc, } une Fin.

Chaque instruction est impérativement suivie d'un point-virgule (;).

Types des variables, variables, assignation

Il existe en Perl trois types de données  les types scalaires, les tableaux classiques et les tableaux associatifs.

Les types scalaires regroupent les types de base vus en cours d'algorithmique  entiers, réels, caractères et chaîne de caractères, etc.

À propos des booléens en perl : 0 ou '' ou () sont faux, le reste est vrai.

En Perl, toutes les variables commencent par un signe particulier, en fonction de leurs types 

  • $ pour les scalaires,
  • @ pour les tableaux classiques,
  • % pour les tableaux associatifs.

Plusieurs notions d'égalité sont à distinguer :

  • l'affectation, symbole =,
  • le test d'égalité entre nombres, symbole ==,
  • le test d'égalité entre chaînes de caractères avec l'opérateur eq.

Lors de la première utilisation d'une variable, nous utiliserons le mot-clef my en guise de déclaration de variable (mais pas de déclaration de type en Perl). Nous pouvons donc écrire par exemple 

my $w;
my $x = 2;
my $y = 3.14;
my $z = 'toto';

Opérateurs en Perl

Nous disposons en Perl des opérateurs arithmétiques classiques : +, -, *, / et de l'opérateur de concaténation entre chaînes de caractères noté par un point.

my $i = 10;
$i    = $i + 1;
$i    = $i + 9;
my $texte = 'La variable i vaut '.$i;
$texte    = $texte."\n";

Remarquons ici que Perl n'a pas de contrôle fort sur les types de variables  une même variable peut subir une opération arithmétique puis une opération propre aux chaînes de caractères sans provoquer d'erreur. Au final, la variable $texte contient donc La variable i vaut 20\n.

Il existe d'autres manières souvent pratiques d'exprimer ces opérations. Par exemple, les opérations ci-dessus sont strictement équivalentes à 

my $i = 10;
$i++;
$i += 9;
my $texte  = 'La variable i vaut '.$i;
$texte .= "\n";

Enfin, Perl propose les habituels

  • opérateurs booléens : &&, ||, !,
  • comparateurs entre entiers : ==, !=, >=, <=,, >, <,
  • comparateurs entre chaînes de caractères : eq, ne, lt, gt, le, ge.

Instruction de sortie et chaînes de caractères Perl

L'affichage est réalisé à l'aide l'instruction print. Cette instruction est particulièrement importante  c'est elle qui va produire le résultat final.

En Perl, les chaînes de caractères sont délimitées soit par des apostrophes, soit par des guillemets. Dans le premier cas, le contenu de la chaîne n'est pas interprété par Perl, dans le second une variable apparaissant dans la chaîne est remplacée par sa valeur.

my $t = 'coucou';
my $v = 5;
print '$v fois $t\n';
print "$v fois $t\n";

Dans cet exemple, le premier affichage produira $v fois $t\n, le second lui affichera 5 fois coucou avec un passage à la ligne ensuite (codé par \n).

Fonctions et procédures en Perl

Définition de fonctions Perl

sub nom_de_la_fonction (paramètres) {
  # des instructions ici
}

Les paramètres ne sont pas précisés par des noms de variables, mais par le symbole de leur type  $, @ ou %. Les valeurs sont transmises dans un tableau noté @_ dont nous prendrons soin d'immédiatement extraire et nommer les valeurs. Par exemple 

sub nom_de_la_fonction ($$) {

  my ($a,$b) = @_;

  # des instructions ici
}

Structures de contrôle en Perl

Modulo les conventions Perl, nous retrouvons les structures de contrôle habituelles. Le si alors sinon 

if (une condition ici) {
  # des instructions ici
} else {
  # des instructions ici
}

autres syntaxes :

# une instruction ici if (une condition ici);
# une instruction ici unless (une condition ici);

La boucle tant que :

while (une condition ici) {
  # des instructions ici
}

Et la boucle pour :

for (my $i=0 ; $i<10 ; $i++) {
  # des instructions ici
}

Un dernier type de boucle existe en Perl mais est dédié au parcours de tableaux.

Structures de données Perl : les tableaux classiques

Dans cette sestion, les tableaux dits classiques : pas de contrainte sur le contenu des cases, celles-ci sont numérotées à partir de 0, et les noms de variables de ce type débutent par @.

Manipulation des tableaux classiques Perl

Tout d'abord l'affectation de valeurs aux cases des tableaux.

# définition d'un tableau vide et remplissage des cases
my @t = ();
$t[0] = 3.14;
$t[1] = 'coucou';
$t[2] = 10;

# syntaxe équivalente
my @t = (3.14,'coucou',10);

# ajout d'un élément en fin
push(@t,2013);

À noter que la taille d'un tableau (c'est-à-dire son nombre de cases) est fournie par la fonction scalar.

# affichage de la taille d'un tableau
print scalar(@t);

Pour obtenir le contenu d'une case choisie au hasard, nous utilisons la fonction rand :

my @t = (3.14,'coucou',10);
print $t[int(rand(scalar(@t)))];

Nous pouvons ordonner les cases d'un tableau avec l'instruction sort.

Parcours de tableaux Perl : la boucle foreach

Enfin, la boucle foreach est dédiée au parcours de tableaux :

foreach my $val (@tab) {
  # des instructions ici portant sur $val
}

Opérations sur les chaînes de caractères et expressions régulières

Basiques sur les chaînes de caractères

Nous rappelons les comparateurs sur les chaînes de caractères :

  • eq,
  • ne,
  • lt,
  • gt,
  • le,
  • ge.

La précision use locale indique d'utiliser les paramètres régionaux par exemple pour comparer alphabétiquement deux mots, sans se tromper sur les mots accentués.

Principales opérations sur les chaînes :

  • length, longueur,
  • symbole . pour concaténer deux chaînes de caractères,
  • index et rindex, recherche de la position d'un sous-chaîne,
  • substr, extraction et substitution,
  • chop, pour enlever le dernier caractère d'une chaîne,
  • chomp, pour enlever l'éventuel caractère de passage à la ligne en fin de chaîne.

Expressions régulières

Caractères spéciaux :

début ^
fin $
caractère quelconque .
un espace \s pas un espace \S
un chiffre \d pas un chiffre \D
une lettre \w pas une lettre \W
une ponctuation [:punct:]
une voyelle [aeiouy] pas une voyelle [^aeiouy]

Quantifieurs :

zéro ou une fois ?
zéro ou plusieurs fois *
une ou plusieurs fois +

Exemple :

  • commence par un S
  • suivi par une voyelle
  • puis par au moins une lettre
  • au moins un espace
  • éventuellement des chiffres pour finir
^{}S[aeiouy]\w+\s+\d*$

Opérateurs sur les expressions régulières

Opérateur de matching, matching, correspondance avec =~ //

     if ($verbe =~ /^[aeiou]/) {
       ...
     }

insensibilité à la casse avec le modifieur i

     if ($verbe =~ /^[aeiou]/i) {
       ...
     }

matching et extraction, parenthèses et variables numérotées.

     $verbe =~ /(..)$/;
     $terminaison = $1;

Opérateur de substitution, substitution avec =~ s/// :

     $verbe =~ s/er$/ons/;

toutes les substitutions avec le modifieur g :

     	$description =~ s/\. /.\n/g;

Opérateur de découpage, découpage avec split :

     my ($num,$nom,$texte) = split(/,/,$ligne);
     my @mots              = split(/\s+/,$ligne);

Gestion des flux et des fichiers

Les instructions perl relatives aux fichiers et aux flux :

  • open
  • close
  • binmode
  • opérateur <FLUX>

Écriture :

open(OUT,">sortie.html");
binmode(OUT,":utf8");
print OUT "<p>coucou !</p>\n";
print OUT "<p>ça va ?</p>\n";
close(OUT);

Lecture :

open(IN,"dico.txt");
binmode(IN,":utf8");
while (my $ligne = <IN>) {
  chop($ligne)
  # traitements de la $ligne
}
close(IN);

Structures de données Perl : les tableaux associatifs

Après les tableaux classiques, nous nous intéressons aux tableaux dits associatifs. Ceux-ci ont la particularité que les cases ne sont plus indicées par un numéro mais par un texte. Les noms de variables de ce type débutent par %.

Vocabulaire et syntaxe des tableaux associatifs

clefs et valeurs

tableau associatif, dictionnaire, table de hachage ou hash (informatique, accès rapide), expliquer le fonction de hachage, risques de collision, etc.

proposer une fonction de hachage sur les mots à partir des numéros de lettre : a(1) b(2) c(3) d(4) e(5) f(6) g(7) h(8) i(9) j(10) k(11) l(12) m(13) n(14) o(15) p(16) q(17) r(18) s(19) t(20) u(21) v(22) w(23) x(24) y(25) z(26)

initialisations et modifications : % {} =>

  • keys (pour récupérer les clefs d'un tableau associatif dans un tableau normal) et values
  • exists
  • {}++ si pas défini ?
  • delete
  • parcours avec foreach-keys, ou avec while-each
  • scalar ne sert à rien sur ce type de données, scalar sur keys pour connaître la taille
  • sort sur les keys et comparateur
    sub parage {
      $age{$a} <=> $age{$b};
    }

    @sortedclass = sort parage @class;

Utilisation de la boucle foreach pour parcourir un tableau associatif :

foreach my $clef (keys %tab) {
  # des instructions ici utilisant $clef et $tab{$clef}
}
while (my ($clef,$val) = each %tab) {
  # des instructions ici utilisant $clef et $tab{$clef}
}

Test d'existence de la clef dans un comptage :

if (exists($comptage{$clef})) {
  $comptage{$clef} = $comptage{$clef} + 1;
} else {
  $comptage{$clef} = 1;
}

Exemples de tableaux associatifs en perl

  • dictionnaires perl, codage d'un vrai dictionnaire mot/définition
  • index mot numéro de pages, moteur de recherche pour ebooks
  • correspondances : traduction, ou chiffrement/déchiffrement par décalage (chiffrement de textes par substitution qui consiste simplement à remplacer systématiquement une lettre par une autre)
  • enregistrements : un mot français et ses rubriques du dictionnaire, un tableau associatif décrit un mot, le nombre d'entrées est figé
  • pour test rapide d'appartenance à un tableau classique mot / 1, discussion vis-à-vis de ~~, plus rapide mais prix à payer ? un benchmark pourrait constituer un exercice (informatique), on va illustrer sur la vérification orthographique
  • applications signature, comme les anagrammeurs : scrabble ou écriture sur mobile
  • compteurs mot-ou-autre-chose / occurences
my %mail = ();
$mail{'torre'} = 'torre@univ.fr';
$mail{'toto'}  = 'toto.machin@free.fr';
print 'Mail de toto = '.$mail{'toto'};

Références en Perl

Retour sur les fonctions perl

Profils, passage, portée. En Perl les paramètres sont passés par valeur, c'est-à-dire que les procédures travaillent sur une copie des objets passés en paramètres.

Ce que reçoit une fonction est forcémment un tableau. Nous l'avons vu quand on voulait simplement passer une unique valeur scalaire... Autre question : comment passer plusieurs tableaux ? Exemple : procédure qui reçoit deux tableaux et dit lequel est le plus grand. Exemple : expliciter la fusion des tableaux.

C'est pourquoi perl interdit d'avoir un profil @@... nous pourrions renoncer aux profils, mais cela ne change pas réellement le problème.

Idem pour les valeurs de retour des fonctions perl : comment retourner plusieurs tableaux ? Exemple : fonction qui partitionne une liste de lettres ?

Autre problématique : si les objets donnés à une procédure sont susceptibles d'être modifiés et si nous souhaitons que ces modifications soient visibles de l'extérieur de la procédure, le passage doit se faire par référence.

Solutions avec les références

notion de référence = une adresse = un entier = un scalaire

obtenir une référence selon l'objet

\$, \@ ou \%

ou à la création avec [] ou {}

déréférencer selon l'objet pointé

$$, @$ ou %$

-> pour les tableaux pointés

déréférencement des tableaux de tableaux, pourquoi les accolades...

Intérêts et applications des références

  • passage de plusieurs tableaux en paramètres
  • modification des paramètres dans une procédure
  • retour de plusieurs tableaux en résultats
  • structures de données complexes

Tableaux de tableaux en Perl

Construction d'un tableau de tableaux en perl

Repartons d'un tableau associatif habituel...

  my %dictionnaire = (

    ...
  
    'aegmnr' => 'manger';

    ...

  );

... qui devient une tableau associatif contenant des tableaux :

  my %dictionnaire = (

    ...

    'aegmnr' => [ 'gramen' , 'magner' , 'manger' ],

    ...

  );

Autre exemple d'un tableau associatif de tableaux :

  @contraintes = (

     [ 'e' , 2 ],
     [ 'x' , 5 ],

  );

Exemple d'un tableau de tableaux associatifs :

  my @dictionnaire = (

    ...

    { 'mot'=>'manger' , 'definition'=>'prendre un repas' }

   ...

  );

Tableaux de tableaux : accès et modification

Sur des exemples :

  my $lettre = $contraintes[1][0];

  my $mot = $dictionnaire{'aegmnr'}[2];

  my @mots = @{ $dictionnaire{'aegmnr'} }

  my %description = %{ $dictionnaire[12] };

  print $description[12]{'definition'};
Fabien Torre Valid HTML5! Valid CSS!
Accueil > Enseignement > Cours > Programmation > Perl
(contenu mis à jour )
site de Fabien Torre, université de Lille

Description

Survoler un lien de navigation pour lire sa description ici...


Une photo au hasard

Cérémonies d'octobre.

(le 17 octobre 2008)

La déesse de Lille, sur la grand'place.