Programmation Perl
Fiche N°4 - Tableaux et hachages

	Tableau (ou liste)	Hash (ou tableau associatif)	
Description	Collection de scalaires repérés par un indice (position)	Collection de paires de scalaires clé=>valeur	
Déclaration	my @tableau;	my %hash;	
Affectation d'un littéral	@table=("janvier","février","mars")	%hash=("bonjour"=>"hello","au revoir"=>"good bye")	
Affectation d'une liste de variable	($mois1,$mois2,$mois3)= ("janvier","février","mars")		
Accès à un élément	Par son indice :
print $table[2]	Par sa clé :
print $hash{"au revoir"}	
Accès au premier élément	print $table[0]	Au premier appel :
($cle,$valeur)=each(%hash);	
Accès au dernier élément	print $table[-1]	Attention : l'ordre des couples n'est pas défini	
Ajout d'un élément	A gauche : unshift(@table,$val). Décale tous les indices d'un cran (incrémentation)
A droite : push(@table,$val)
A l'intérieur de la liste. Insertion des éléments de @nouveaux à la position $i :
splice(@table, $i, 0, @nouveaux)	Par affectation
$hash{"à bientôt"}="see you soon"	
Suppression d'un élément	A gauche : $val=shift(@table)
Décale tous les indices d'un cran (décrémentation)
A droite : $val=pop(@table)
A l'intérieur de la liste. Suppression de $n élément à partir de l'indice $i :
splice(@table, $i, $n) 	delete ($hash{"à bientôt"});	
Test de la présence d'un élt	if ($i<=$#table) {print $table[$i]}	if (exists($hash{"à bientôt"})) { 
print $hash{"à bientôt"}; }	
Parcours de tous les éléments	foreach $elt (@table) { bloc } 
ou 
for ($i=0;$i<=$#table;$i++) { bloc }	1/ Avec la fonction each( ) qui renvoie d'abord le premier couple (clé,valeur), puis à chaque itération le prochain couple, puis 0.
while (($cle, $valeur) = each(%hash)) { print $cle." ".$valeur }
2/ Avec la fonction keys( ), qui renvoie la liste des clés.
@listeCle=keys(%hash);
foreach $cle (@listeCle) { $valeur=$hash{$cle}; }	
Tri	@tabletriee=sort(@table);	@cletriee=sort(keys(@table))	
Divers	Inverser l'ordre d'une liste
@table2=reverse(@table);
Fusionner une liste en chaîne de car.
$chaine=join(",",@table);
Filtrer une liste :
@moisEnR=grep(/r/, @table)	Savoir si un hachage est vide :
if (%h eq 0) { }	

Exercices

Le dictionnaire ABU est constitué de lignes tabulées de la forme
cabriole	cabriole	Nom:Fem+SG
cabriole	cabrioler	Ver:IPre+SG+P1:IPre+SG+P3:SPre+SG+P1:SPre+SG+P3:ImPre+SG+P2
cabriolent	cabrioler	Ver:IPre+PL+P3:SPre+PL+P3
cabriolera	cabrioler	Ver:IFut+SG+P3

a) Peut-on créer un hachage permettant d'enregistrer, pour chaque forme fléchie, le lemme et la liste de traits correspondants ?

b) Créer un hachage permettant d'enregistrer, pour chaque forme fléchie, la liste des lemmes potentiels avec les catégories correspondantes. Cette liste sera une chaîne de la forme : "lemme-cat1 lemme-cat2  ". P. ex. on aura :
cabriole => "cabriole-Nom cabrioler-Ver"

c) Afficher le hash trié par la fin des clés
Fonction de tri explicite
Il est possible de redéfinir explicitement la relation d'ordre pour le tri. On désigne par $a et $b deux éléments à comparer. L'opérateur de comparaison alphanumérique est cmp et l'opérateur de comparaison numérique est <=>. 
@listeTriée = sort {$a cmp $b } @listeATrier	# tri alphanumérique
@listeTriée = sort {$a <=> $b } @listeATrier	# tri numérique
Pour un tri inverse, on joue simplement sur les positions de $a et $b par rapport aux opérateurs :
@listeTriée = sort {$b cmp $a } @listeATrier	# tri alphanumérique inverse
@listeTriée = sort {$b <=> $a } @listeATrier	# tri numérique inverse
Pour redéfinir totalement la relation d'ordre, on peut faire entrer $a et $b dans des expressions complexes
@listeTrié = sort {length($a) <=> length($b) } @listeATrier	# tri par longueur croissante

d) Afficher la liste de tous les noms se terminant par -eur. 
Sélection d'éléments : grep
Syntaxe : grep {bloc} @list ou grep EXPR, @list
Grep renvoie la sous-liste des éléments pour lesquels le bloc (ou l'expression) est évalué à vrai (1).
Dans la définition du bloc, ou de l'expression, les éléments sont représentés par $_ (la var. par défaut). 
@mois=("janvier","février","mars",..,"décembre");
@l=grep { length($_)> 8 } @mois;	# donne la liste des mois dont la longueur est supérieur à 8
@l=grep /r/ @mois ; 		# donne la liste des mois qui contiennent un "r"
Le bloc peut contenir une suite d'instructions, voire un programme entier.
@l=grep { my $l= length($_); if ($l<= 8 && $_!~/r/) { return 1 } } @mois ; # intersection des deux listes précédentes.

e) Créer une fonction prenant comme argument deux chaînes, une catégorie et un suffixe, et qui écrit dans un fichier select.txt la liste des formes correspondantes. Le dictionnaire sera enregistré comme variable globale.

f) Créer une fonction convertissant un texte brut en texte au format cesAna, segmenté et tokenisé, comportant les informations sur les lemmes (base) et les catégories (ctag).

Exemple de codage cesAna

<!doctype cesAna PUBLIC "-//CES//DTD cesAna//EN" 
<cesAna version="1.5" type="SENT TOK LEX DISAMB" doc=MyText1>
<cesHeader version="2.3">
    ...
</cesHeader>
  <chunkList>
    <chunk doc="MyText1" from='1.2.1\1'>
      <s >
        <tok class='tok' from='1.2.1\1'>
          <orth>Les</orth>
          <disamb>
              <ctag>DMP</ctag>
          </disamb>         
          <lex>
              <base>le</base>
              <msd>Da-fp--d</msd>
              <ctag>DFP</ctag>
          </lex>
          <lex>
              <base>le</base>
              <msd>Da-mp--d</msd>
              <ctag>DMP</ctag>
          </lex>
          <lex>
              <base>le</base>
              <msd>Pp3fpj-</msd>
              <ctag>PPJ</ctag>
          </lex>
          <lex>
              <base>le</base>
              <msd>Pp3mpj-</msd>
              <ctag>PPJ</ctag>
          </lex>
        </tok>
        <tok class='tok' from='1.2.1\5'>
          <orth>critères</orth>
          <disamb>
              <ctag>NCMP</ctag>
          </disamb>         
          <lex>
              <base>critère</base>
              <msd>Ncmp-</msd>
              <ctag>NCMP</ctag>
          </lex>
        </tok>
        <tok  class='tok' from='1.2.1\14'>
          <orth>se</orth>
          <disamb>
              <ctag>PPJ</ctag>
          </disamb>         
          <lex>
              <base>se</base>
              <msd>Pp3msj-</msd>
              <ctag>PPJ</ctag>
          </lex>
          <lex>
              <base>se</base>
              <msd>Pp3fpj-</msd>
              <ctag>PPJ</ctag>
          </lex>
          <lex>
              <base>se</base>
              <msd>Pp3fsj-</msd>
              <ctag>PPJ</ctag>
          </lex>
          <lex>
              <base>se</base>
              <msd>Pp3mpj-</msd>
              <ctag>PPJ</ctag>
          </lex>
        </tok>
        <tok  class='tok' from='1.2.1\17'>
          <orth>basent</orth>
          <disamb>
              <ctag>VM3P</ctag>
          </disamb>         
          <lex>
              <base>baser</base>
              <msd>Vmip3p--</msd>
              <ctag>VM3P</ctag>
          </lex>
          <lex>
              <base>baser</base>
              <msd>Vmsp3p--</msd>
              <ctag>VM3P</ctag>
          </lex>
        </tok>
        <tok  class='tok' from='1.2.1\24'>
          <orth>sur</orth>
          <disamb>
              <ctag>SP</ctag>
          </disamb>         
          <lex>
              <base>sur</base>
              <msd>Afpms-</msd>
              <ctag>AMS</ctag>
          </lex>
          <lex>
              <base>sur</base>
              <msd>Sp</msd>
              <ctag>SP</ctag>
          </lex>
        </tok>
        ...
      </s>
    </chunk>
  </chunkList>
    </cesAna>