Cours théorique 4

Librairies, modules, objets

Pourquoi une librairie?

Une librarie simple : require

require "fichier.pl";

Pour les collections de fonctions relativement simple.

Pour faire une librairie : simplement mettre les fonctions à réutiliser dans un fichier, s'assurer que le fichier retourne "vrai" (une ligne comme "1;" à la fin fait l'affaire) et voilà!

Les "vraies" librairies : use et package

use Librairie;

Les librairies distribuées sur le CPAN sont toutes distribués dans des package

Avantage vs require :

Créer un package:

package malibrarie;

#fonctions ici
     

Par défaut, les fonctions ne sont pas exportés. Pour les appeler, le script qui appelle va faire comme ca :

use malibrairie;

print malibrairie::mafonction();

Pour exporter :

package Some::Module;  # assumes Some/Module.pm

    use strict;
    use warnings;

    BEGIN {
        use Exporter   ();
        our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);

        # set the version for version checking
        $VERSION     = 1.00;
        # if using RCS/CVS, this may be preferred
        $VERSION = do { my @r = (q$Revision: 2.21 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker

        @ISA         = qw(Exporter);
        @EXPORT      = qw(&func1 &func2 &func4);
        %EXPORT_TAGS = ( );     # eg: TAG => [ qw!name1 name2! ],

        # your exported package globals go here,
        # as well as any optionally exported functions
        @EXPORT_OK   = qw($Var1 %Hashit &func3);
    }
    our @EXPORT_OK;

    # exported package globals go here
    our $Var1;
    our %Hashit;

    # non-exported package globals go here
    our @more;
    our $stuff;

    # initialize package globals, first exported ones
    $Var1   = '';
    %Hashit = ();

    # then the others (which are still accessible as $Some::Module::stuff)
    $stuff  = '';
    @more   = ();

    # all file-scoped lexicals must be created before
    # the functions below that use them.

    # file-private lexicals go here
    my $priv_var    = '';
    my %secret_hash = ();

    # here's a file-private function as a closure,
    # callable as &$priv_func;  it cannot be prototyped.
    my $priv_func = sub {
        # stuff goes here.
    };

    # make all your functions, whether exported or not;
    # remember to put something interesting in the {} stubs
    sub func1      {}    # no prototype
    sub func2()    {}    # proto'd void
    sub func3($$)  {}    # proto'd to 2 scalars

    # this one isn't exported, but could be called!
    sub func4(\%)  {}    # proto'd to 1 hash ref

    END { }       # module clean-up code here (global destructor)

    ## YOUR CODE GOES HERE

    1;  # don't forget to return a true value from the file  
     

h2xs : pour démarrer rapidement

h2xs -AX -n Net::Acme (-A : no Autoload, X, no XS)

Les expressions régulières

Le concept

Un sous langage qui permet de définir un "pattern" a accrocher.

La logique : on décrit à l'aide de symboles la chaine de caractère qui correspond à ce qu'on recherche

Où les utiliser?

Dans une "regexp" proprement dite :

     $var = '17h23';
     if ($var =~ /\d{2}h\d+/){
	 print "C'est une heure";
     }
    

Dans une substitution :

	while(<>){
	    s/[Pp]earl/Perl/g;
	    print;
	}
    

Dans une "translation" :

	while(<>){
	    tr/[a-z]/[b-z]/;
	    print;
	}
    

Selon la documentation

Plusieurs fonctions acceptent des expressions régulières comme paramètres. L'endroit le plus commun : split :

@separe_par_nombre_quelconque_d_espaces_ou_de_tab = split /\s+/, $chaine;

@espace_deux_points_espaces = split /\s*:\s*/, $chaine;

Le "langage"

Composer une expression régulière

Les expressions régulières forment des "patrons" (ou pattern, comme pattern matching).

Le patron le plus simple : un simple mot :

     if ("Hello World" =~ /World/){
	 print "yep!";
     }

On peut inverser le match avec l'opérateur !~ :

  if ("Hello World" !~ /monde/){
    print "nein!";
  }
On peut également remplacer les // par d'autres caractères en annoncant qu'on fait une regexp avec un m:
   while($ligne = <>){
	  $ligne =~ m|/pour/un/path/de/fichier/|;
	  # les ## sont reconnus comme caractere de match, et non comme commentaires...
	  $ligne =~ m#hello#; 
	  $ligne =~ m(z); 
	  # exceptions : les () et {} sont 
	  # reconnus en ouvrant et fermant
   }

Une expression régulière est comme une chaine "double guillemets" : les variables y sont remplacé :

     $qui = 'monde';

     if ("Salut le monde" =~ /$qui/){
	    print "hello, ca marche";
     }

Les "patrons"

On a déjà vu le patron le plus simple : un mot ou une lettre. Toutes les lettres sont alors légale, sauf les métacaractères :

{ } ( ) [ ] ^ $ . | * + ? \

On peut composer des patrons plus complexes avec ces métacaratères.

Caratères spéciaux :

Les caractères spéciaux peuvent être interceptés avec les méta, comme dans les chaines "" :

    \n - Saut de ligne
     \t - Tabulation
     \x61 - Match le code du caracteres, en hexa
     ...

Des classes de caractères peuvent également être interceptés avec ces constructions :

     \d : un caractère numérique ("digit")
     \D : N,est pas un "digit"
     \w : un caractère qui forme un mot : comme pour une variable
     \W : pas un mot
     \s : un "espace" : une tabulation, un espace, un saut de ligne...
     \S : tout sauf une "espace"
     ....

Controle des répétitions :

Les méta *, +, ? et {} servent a controler les répétitions de caractères :

     "Hello" =~ /hel+o/; # l+ : l 1 ou plusieurs fois
     "hello" =~ /hello?/; # o? : o zéro ou une fois.
     "hello" =~ /hello!/; # Donc, ca aussi c'est vrai
     "hello" =~ /hel{2}o/; # l{2} : l 2 fois exactement
     "helllo" =~ /hel{2,3}/; # l{2,3} : l 2 ou 3 fois
     "hellooooo" =~ /hello{2,}/; # o 2 fois ou plus
     

On peut aussi regrouper des parties du patrons pour choisir entre 2 choix :

     "Hello World" =~ /(He|A)llo (World|le monde)/;

Ou choisir dans une série de caracteres

$var =~ /[rcp]at/; #va matcher rat, cat ou pat

On peut inverser la logique :

     $var =~ /[^rcp]at/; #va matcher at précédé par quelque chose, sauf r, c ou p 
   
Une série de caractères :
     $var =~ /[a-j]/; # N'importe quel caractère entre a et j
     $var =~ /[0-9]/; # Autre facon d'accrocher un chiffre
    

Et on peut faire correspondre n'importe quel caracteres :

     "hello world" =~ /he..o world/; # match hello, mais aussi heppo, he((o, he22o, he__o, etc.
     
Pour "attacher" un mot à un bout ou l'autre de la chaine, on utilise ^ ou $ :
   "Hello World" =~ /^Hello/; # match Hello au début
     "Hello World" =~ /Hello$/; # Ne match PAS ; aurait du terminé la chaine par Hello
     "Hello World" =~ /^H.*d$/; # Match n'importe quoi qui commence par H et fini par d : Howard aurait fait.
Intercepter une partie de la chaine :

Supposons un fichier qui contient des lignes comme suit :

     TP 1 : 18 / 20
     TP 2 : 16 / 20

Pour intercepter la valeur des données, on pourrait procéder comme ca :

 
    while (<>){
	   if (/TP (\d) : (\d{2}) \/ (\d{2,3})/){
	     $notes{$1} = "$2 sur $3";
	   }
    }
    foreach $k (sort keys %notes){
	   print "TP $k : $notes{$k}\n";
    }
    

Les parenthèses permettent d'intercepter la chaine. Les valeurs interceptés vont dans $1, $2, $3, ...