PERL POUR LA MANIPULATION DE TEXTES Une Introduction par l
Transcription
PERL POUR LA MANIPULATION DE TEXTES Une Introduction par l
PERL POUR LA MANIPULATION DE TEXTES Une Introduction par l'exemple Sous linux, on peut exécuter un script perl en tapant dans un terminal laligne de commande $ perl nom_du_programme.pl Les exemples suivants, introduisent de manière graduelle les éléments de syntaxe du langage perl. EXEMPLE 1 : L'exemple suivant introduit une manière de traiter un fichier externe. Pour tous les exemples suivants on va utiliser un fichier test.txt qu'il faudra copier dans le répertoire Perl. =========== #!/usr/bin/perl # imprime un texte avec chaque ligne précédée par un numéro de ligne. # perl numerote_lignes.pl test.txt $fich =shift ; open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; while (<FICHIER>) { print "$. : $_"; } print "\n$. lignes en tout\n\n"; ============ La première ligne de n'importe quel programme perl doit être (ne jamais omettre cette ligne de code!!) : #!/usr/bin/perl Cette ligne indique au système d'exploitation où trouver Perl. (Elle indique le chemin d'accès absolu jusqu'à l'interpréteur) Les lignes suivantes, précédées par le symbole # sont des lignes de commentaire. Elles seront ignorées lors de l'exécution du script. La ligne $fich= shift; permet de récupérer le nom du fichier qu'on cherche à traiter sur la ligne de commande. Ceci nous permet de traiter n'importe quel fichier en utilisant le même script. Ce nom est stocké dans une variable : $fich, dont on pourra se servir par la suite pour faire référence au fichier. Dans notre cas, la valeur de cette variable, inchangée tout au long de ce script sera la chaîne de caractères "test.txt". La ligne open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; permet d'ouvrir le fichier test.txt (la variable $fich vaut dans notre cas "test.txt"), et FICHIER est un descripteur dont on pourra se servir par la suite pour lire dans le fichier $fich, qui vaut en l'occurrence test.txt. Si cette action échoue, parce que le fichier désigne par $fich n'existe pas, (on peut tester ce cas avec un fichier bidon toto.txt), le programme s'arrête avec le message : Impossible d'ouvrir le fichier : toto.txt while (<FICHIER>) { ... } indique qu'on cherche à exécuter les actions qui suivent pour chaque ligne du texte à traiter, en l'occurrence FICHIER, qui est le "descripteur " de test.txt. While est un exemple de structure de contrôle qui instruit le système de répéter ou itérer une action (ou une suite d'actions) tant qu'une condition tient. La syntaxe générale de la structure while est while (condition) { action ; action; ... } Dans l'exemple présent, la condition est 'tant qu'il y a des lignes a lire'. Cette expression est exprimée par l'opérateur <>. Les actions à accomplir (ici l'action d'imprimer à l'écran) sont encadrées pas les guillemets. La ligne print "$. : $_"; fait appel à deux variables spéciales, prédéfinies en perl : $. désigne le numéro de la ligne courante $_ désigne la ligne courante et à l'opérateur print. Un opérateur instruit le système à accomplir une certaine tâche. Le résultat de cette instruction est l'impression à l'écran du numéro de la ligne courante, suivi du signe : , suivi de la ligne courante. Finalement, la ligne print "\n$. lignes en tout\n\n"; permet d'imprimer, une fois que chaque ligne du fichier a été traitée, le nombre total de lignes du fichier (lors de la dernière itération/répétition de la boucle while, la valeur de la variable $_ est la dernière ligne du fichier et la valeur de $. est le numéro de la dernière ligne - on peut donc se servir de cette dernière pour imprimer le nombre total de lignes du fichier.). EXEMPLE 2 : ====================== #!/usr/bin/perl # imprime un texte avec chaque ligne précédée par un numéro de ligne. # perl ....._lignes.pl test.txt $fich=shift ; open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; while (<FICHIER>) { $len=length($_); print "$len : $_"; } print "\n$. lignes en tout\n\n"; ====================== Exécuter le programme no 2. Que permet de faire ce programme? Ce programme introduit un élément supplémentaire qui est la fonction prédéfinie length. Que permet de faire cette fonction? EXEMPLE 3 : Que permet de faire le script suivant? Les deux scripts introduisent trois éléments de plus : la structure de contrôle if, l'incrémentation des variables et les opérateurs d'égalité sur des chaînes de caractères : eq c-à-d equals (permettant de tester l'égalité) ou ne c-a-d not-equals (qui permet de tester que deux chaînes de caractères sont différentes). Cet opérateur aurait pu être utilisé à la place de eq en inversant l'ordre des blocs if-else. Comment? ============================== #!/usr/bin/perl #Ce script permet de .... # $fich=shift ; open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; $nombre_lignes_vides = 0 ; $nombre_lignes_non_vides =0; while (<FICHIER>) { if ($_ eq "\n"){ $nombre_lignes_vides++; }else{ $nombre_lignes_non_vides++; } } print "lignes vides : ", $nombre_lignes_vides, " et lignes non-vides : ", $nombre_lignes_non_vides, "\n"; ##print "lignes vides : $nombre_lignes_vides $nombre_lignes_non_vides\n\n"; et lignes non-vides : ======================= Deux variables son introduites avant le debut de la boucle while : $nombre_lignes_vides et $nombre_lignes_non_vides. Ensuite, dans la boucle while chaque ligne du corpus est traitée. Si elle correspond à la condition définie dans la branche if, alors la variable $nombre_lignes_vides est incrémentée, sinon c'est la variable $nombre_lignes_non_vides qui est incrémentée. NOTE : la notation $nombre_lignes_vides ++ est équivalente à la notation $nombre_lignes_vides =$nombre_lignes_vides+1; Les deux instructions permettent d'affecter à la variable $nombre_lignes_vides son ancienne valeur incrémentée de 1. EXEMPLE 4 : Que permet de faire le script suivant? Il utilise la plupart d'éléments qu'on a déjà rencontrés plus l'opérateur de comparaison > (supérieur). Dans notre exemple, cet opérateur permet de comparer deux quantités numériques. L'exemple montre aussi que le bloc else dans une structure if-else est optionnel. =================== #!/usr/bin/perl # ce script permet de ..... $fich=shift ; open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; $max=0; while (<FICHIER>) { $len=length($_); if ($len > $max){ $max=$len; } } print "MAXIMUM: $max\n"; =================== EXEMPLE 5 : Que permet de faire le script suivant? ================== #!/usr/bin/perl # ce script permet de .................................... $fich=shift ; open(FICHIER, $fich) || die "Impossible d'ouvrir le fichier : $fich\n"; while (<FICHIER>) { tr/A-ZÂÀÄÉÈÊËÎÏÔÖÓÛÙÜÇÑ/a-zâàäéèêëîïôöóûùüçñ/; s/([0-9]+) ([0-9]+)/$1$2/g; s/ ([sdlmntcj]')([a-z]+)/ $1\n$2/g; s/^([dlmntcj]')([a-z]+)/$1\n$2/g; s/(qu|jusqu|lorsqu)'/$1'\n/g; tr/\t//d; s/\.\n/\n.\n/; s/([,\.]) /\n$1 /g; tr/ /\n/; print $_; } ====================== Certains éléments qu'on avait vus lors des séances de familiarisation avec l'environnement Linux, mais leur syntaxe est légèrement différente : tr permet de transformer des ensembles de caractères (ici les majuscules en minuscules). NOTE : les deux ensembles de caractères doivent être de taille égale. s permet d'effectuer des substitutions sur des chaînes de caractères. Cette instruction permet de manipuler aussi des expressions régulières. $1 et $2 font référence à la première et deuxième sous-expression d'une expression régulière, qu'on souhaite réutiliser dans les substitutions. Ces deux variables spéciales sont l'équivalent des variables \1 et \2 qu'on avait vu avecla commande grep). Reprenons tour à tour les éléments du langage perl qu'on a vu jusqu'ici, et examinons-les d'une manière plus approfondie : Les variables L'opérateur print. Variables scalaires : - affectation d'une valeur - opérateurs de comparaison Les structures de contrôle Substitutions et transformations sur les chaînes decaractères Ouverture des fichiers et lecture PREMIERE PARTIE 0/ Qu'est-ce que perl et qu'est-ce qu'on peut faire avec perl? 1/ Les variables : scalaires, tableaux, tableaux associatifs 2/ L'opérateur print. 3/ Variables scalaires : - affectation des valeurs - opérateurs de comparaison sur les valeurs scalaires(nombres et chaînes de caractères) - substitutions et transformations sur les chaînes de caractères 4/ Les structures de contrôle 5/ Ouverture des fichiers 0/ Qu'est-ce que Perl et pourquoi on s'y intéresse? Perl (Practical Report and Extraction Language ou Pathological Eclectic Rubbish Lister) est un langage de programmation. Il est particulièrement adapté pour le traitement des fichiers textes (et les CGI). On l'utilise principalement pour la facilité avec laquelle on peut développer des programmes la puissance du mécanisme des expressions régulières simplicité - possibilité de faire des manipulations de textes sans prendre des cours de programmation avancés. (On arrive à faire pas mal de choses même en étant débutants). les programmes écrits en Perl peuvent être exécutés sous Unix, Windows, Mac, etc sans modification (portable) gratuité : un nombre impressionnant de librairies et utilitaires est disponible sur internet 1/ Les variables Un programme informatique gère des données qu’il stocke en mémoire. On nomme ces données pour pouvoir accéder aux zones de la mémoire centrale les contenant. Ces données peuvent changer au cours de l'exécution d'un programme : donc les noms qu'on leur donne correspond à des variables. Par exemple, dans le script 4, la variable $max peut changer de valeur a chaque répétition de la boucle while. De même, dans le script no. 3 les variables $nombre_lignes_vides et $nombre_lignes_non_vides, qui au début du script valent 0 toutes les deux - on dit qu'elle sont initialisées à 0, changent alternativement de valeur. Pour mieux se représenter ce que c'est qu'une variable et sa valeur on peut utiliser la métaphore de la boite aux lettres : une variable est comme une boite aux lettres nommée, et sa valeur est son contenu à un moment donné. Il existe plusieurs types de variables qu'on manipule enPerl : 1. des scalaires : des variables ayant une valeur simple, qu'on peut manipuler simplement. Tel est le cas des nombres entiers (comme 2, 30, etc. comme - les variables $max, $length, $nombre_lignes_vides ont des valeurs de ce type), nombres flottants (comme 20,35) et les chaînes de caractères (comme la variable $fich qui prend sa valeur sur la ligne de commande). Les valeurs des chaînes de caractères sont entourées de guillemets simples ou doubles. Le nom des variables est précédé du signe $. 2. tableaux (on reviendra sur ce type de valeur lors de la prochaine séance). Un tableau représente une liste de valeurs scalaires ordonnées; chaque élément d'un tableau est une variable scalaire. Les noms de variables de type tableau sont précédés par le symbole @. Par exemple, on peut stocker une ligne qu'on lit dans un fichier dans un tableau afin d'effectuer certaines opérations dessus: @ligne=("the", "cat", "is", "on", "the", "mat", "."); On peut se représenter cette variable comme ceci : The cat 0 1 is 2 on 3 the 4 mat 5 . 6 Chaque élément du tableau est placé dans une case du tableau (une zone mémoire associée) à laquelle on peut accéder à l'aide de l'indice de la case. NOTE : les indices dans un tableau commencent à 0. Par exemple, si on vert accéder au 5ème mot de la phrase (qui aura donc l'indice 4) on va utiliser la notation : $ligne(4) La valeur de cette variable scalaire (chaîne de caractères) vaut "the". Lors de la lecture de la ligne suivante d'un fichier, la taille et la valeur d'une variable tableau change : @ligne=("the", "cat", "is", "sick", "and", "is", "waiting", "to", "get", "better", "."); $ligne(4) vaut maintenant "and". 3. hachages ou tableaux associatifs. (On reviendra sur ce type de valeur dans deux séances). Les tableaux associatifs sont une type particulier de tableau. Tandis que les éléments d’un tableau sont indexés à partir de 0, les éléments d’un hachage sont indexés par une valeur scalaire quelconque. Il s'agit d'une collection de paires clé-valeur. La clés par laquelle les éléments sont indexés doit être unique. Les noms des valeurs des variables de type associatif sont précédés par le symbole %. Un exemple qui permet de se représenter le type tableau associatif d'une façon simple est le type dictionnaire. Par exemple : %dico = ("cat" =>"Any animal of the natural family Felidae", "mat" => "A thick flat fabric", "sick" => "Affected with disease of any kind"); Ou alors %dico = ("cat" =>"Nom", "mat" => "Nom", "sick" => "Adjectif"); Les symboles $,@,% permettent de repérer les variables plus facilement, et indiquent aussi de quel type de variable il s'agit. Regardons maintenant plus en détail les valeurs scalaires (avec une valeur singulière), après une courte digression sur l'opérateur print. 2/ L'opérateur print Il s'agit d'un opérateur qui prend en argument une liste (on peut imprimer plusieurs choses, séparées pas des virgules), comme on a fait dans le script 3 : print "lignes vides : ", $nombre_lignes_vides, " et lignes non-vides : ", $nombre_lignes_non_vides, "\n"; L'opérateur print a, dans ce cas, 5 arguments. On aurait pu écrire la même chose en incluant les variables et le texte à imprimer dans une même chaîne de caractères. Cette opération s'appelle interpolation des variables : print "lignes vides : $nombre_lignes_vides et lignes non-vides : $nombre_lignes_non_vides \n"; L'interpolation des variables est possible uniquement avec les guillemets doubles. 3/Variables scalaires : nombres et chaînes de caractères Vous avez peut-être remarqué dans les exemples de scripts qu'on a étudiés que les variables nombre et chaînes de caractères sont déclarées de la même façon, sans indiquer le type comme ceci : $max=0; ####(entier) $nombre1=12.5 ; $mot="cat"; #### (nombre réel) ####(chaîne de caractères) A l'aide de l'opérateur print on peut les imprimer les trois variables comme ceci : print "\$max vaut $max, \$nombre vaut $nombre et \$mot vaut $mot\n"; REMARQUE : on a du protéger ici le symbole $ afin de pouvoir l'imprimer, et éviter que l'opérateur print affiche la valeur de $max, $nombre1 et $mot. Tous les méta-caractères comme $,@ et % doivent être protégés de cette façon fin de pouvoir les imprimer. A la différence de Perl, dans la plupart de langages de programmation on doit déclarer le type de chaque variable. Par exemple, en C, une déclaration+initialisation comme : $nb_lignes_vides =0 ; devra indiquer le type de la variable qu'on veut déclarercomme ceci : int nb_lignes_vides = 0; Cette ligne déclare la variable nb_lignes_vides de type entier, et lui affecte une valeur initiale qui est égale à 0. C'est pour cette raison que Perl est appelé un langage faiblement typé. C'est à cause de cette manque de rigueur que Perl n'est pas utilisé pour de gros développement de programmes, mais plutôt pour de petites moulinettes. Déclarer et modifier les valeurs des scalaires. Afin d'illustrer ces concepts regardons les deux scripts suivants : #!/usr/bin/perl $nombre = 20 ; $nb = 3 ; $nombre ++; print "\$nombre vaut $nombre--; print "\$nombre vaut $nombre +=22; print "\$nombre vaut $nombre -= 22 ; print "\$nombre vaut $nombre*=$nb ; print "\$nombre vaut $nombre /=$nb ; print "\$nombre vaut $nombre=$nombre**3 ; print "\$nombre vaut $nombre maintenant\n"; $nombre maintenant\n"; $nombre maintenant\n"; $nombre maintenant\n"; $nombre maintenant\n"; $nombre maintenant\n"; $nombre maintenant\n"; ==================== #!/usr/bin/perl $prenom = "Marion" ; $nom = "Vallet"; $nom = $prenom." ".$nom." "; print "\$nom vaut maintenant $nom\n"; ===================== Quel est le rôle de la fonction chop? ===================== #!/usr/bin/perl print "Entrez votre nom s'il vous plaît\n"; $nom= <STDIN>; print "*$nom*\n"; ### pourquoi le deuxième symbole * est-il imprimé sur une autre ligne? chop $nom; print "maintenant \$nom vaut *$nom*\n"; chop $nom; print "maintenant \$nom vaut *$nom*\n" ; ====================== Cet exemple introduit aussi un descripteur prédéfini <STDIN> ou standard input - c'est à dire l'entrée standard. Il permet de lire la valeur d'une variable au clavier. On reviendra sur les descripteurs de fichiers lors de la prochaine séance. Les descripteurs de fichiers permettent d'interagir avecles fichiers, la console d'entrée, etc. Quelle est la différence entre l'opérateur chop et chomp (à juger par le script ci-après? #!/usr/bin/perl print "Entrez votre nom s'il vous plaît\n"; $nom= <STDIN>; print "$nom\n"; chomp $nom; print "maintenant \$nom vaut *$nom*\n"; chomp $nom; print "maintenant \$nom vaut *$nom*\n" ; =======================