Bonus Perl !
Notre script bash achevé, nous avons décidé de nous lancer dans une nouvelle (més)aventure : concevoir un traitement similaire en perl. Les scripts de base en main, nous avons alors tenté de reproduire, non sans mal, les différents processus que nous avions mis en place sous bash.
Le résultat n'est pas tout à fait à la hauteur de nos attentes, mais nous attendons avec impatience le prochain projet pour nous améliorer !
Vous trouverez ci-dessous une petite description, non exhaustive, de quelques notions liées à la syntaxe de Perl et aux commandes utilisées dans le script.
Bonus "$dico" : l’intégration de cette notion, qui permettait dans le script bash d’informer l’utilisateur de l’extraction d’un mauvais sens dans le contenu textuel, n’a pas été aussi simple que nous le pensions. En effet, il ne nous a pas été possible de l’incorporer au mieux malgré de nombreuses tentatives.
Nous nous sommes alors rabattus sur une solution plutôt ‘basique’, la seule qui voulait bien fonctionner sans faire trop d’erreurs : une condition ‘if’ était placée hors de la boucle 'while' afin que le programme informe l’utilisateur (en ajoutant une ligne à la fin du fichier contexte) s’il avait rencontré le motif non désiré dans le contexte déjà créé (code de la solution de secours et exemple de résultat).
Néanmoins, cette solution basique n’a pas été suffisante : pour des raisons qui nous échappent, le traitement bloquait pour certaines URLs et le programme ne pouvait donc poursuivre le parcours et le traitement des urls suivantes.
Finalement, n’ayant aucune autre solution en vue, nous nous sommes vus contraints d’abandonner cette idée… c’est bien dommage.
URLs en chinois : nous avons été dans l'impossibilité de les traiter car la commande get(url) n'aspirait pas ces pages, bien que les procédures étaient sensées encoder en utf-8 et que nous ayons essayé en sus d'encoder en utf-8 les entrées et les sorties de fichiers (avec la commande open(fichier,">:encoding(UTF-8)",$fichier) ou encore decode ("utf-8", $URL)...).
Après maintes tentatives, toutes autant inefficaces les unes que les autres, nous nous sommes résolus (encore une fois!) à abandonner leur traitement.
Perl présente plusieurs caractéristiques :ce langage est souple, simple mais puissant : il se veut pratique et facile à utiliser, plutôt qu’élégant et compact ;
il combine plusieurs fonctionnalités issues de C, sed, awk et sh ;
il est optimisé pour l’extraction d’informations de fichiers texte et la génération de rapports, traitements qui étaient parfois "limités" avant sa création, mais il est également utilisé dans une large gamme de tâches (administration système, développement web, programmation réseau, création d’interfaces graphiques, etc.).
Pour en savoir plus...
Il existe trois types de variables en perl dont les deux suivantes (utilisées dans le script), qui peuvent prendre comme valeur différents types de données :
$cdc = "chainedecaractères"
$nb = nombre
$var = $variable
@nom_tab=('toto',"$var",3)
! Attention ! Une chaîne de caractères encadrée par des apostrophes s’affiche telle qu’elle a été saisie (elle n'est pas interprétée par Perl, contrairement au contenu des guillemets doubles).
$var = "toto";
print
"$var\n"; # Affiche : toto
print
'$var\n'; # Affiche : $var\n
Remarque sur la portée des variables : une variable perl est par défaut 'globale', visible dans l'ensemble du code (c'est-à-dire accessible telle quelle, avec la même valeur assignée une seule fois).
Lorsque l'on veut restreindre la visibilité d'une variable à un bloc d'instructions (et rendre ainsi la variable 'locale'), on utilise la fonction
On peut par la suite modifier sa valeur sans utiliser
$_ : variable contenant la valeur courante (par exemple, si on lit une un fichier ligne par ligne à l'aide de la boucle
Elle peut également s'utiliser de manière implicite (sans être mentionnée)
@ARGV : variable contenant la liste des arguments passés sur la ligne de commande au script en cours d'exécution.
Comme $_, elle peut s'utiliser de manière implicite
@_ : variable contenant les arguments passés au sous-programme en cours (les routines
$@ : variable contenant le message d'erreur fatale du dernier
Si $@ est vide, cela signifie que le dernier
$! : variable contenant le message d'erreur fatale du dernier
(vide lorsque l'instruction précédant
$1, $2, ... : ces variables permettent de faire des références arrières (mémorisation) sur le contenu d'une expression régulière.
Exemple : dans $motif=~ (directions?|\\w*-ways?|ways?), $1 a pour valeur "direction", "directions", "-way", "-ways", "way" ou "ways".
$`, $& et $': ces variables sont utilisées pour définir ce qu'il y a autour du motif reconnu par une expression rationnelle.
$` aura pour valeur la partie de la chaîne qui est avant ce qui a été reconnu,
$& aura pour valeur la partie de la chaîne qui a été reconnue,
et $' aura pour valeur la partie de la chaîne qui est après ce qui a été reconnu.
Remarque : pour la concaténation des valeurs que peut prendre une même variable, on utilise $var
Opérateurs de comparaison numérique
Opérateurs de comparaison de chaînes
Opérateurs booléens
Comme tout langage de programmation, Perl possède une structure conditionnelle.
Elle permet de conditionner l'exécution d'instructions : si la condition est vérifiée, le bloc d'instructions (els)if sera exécuté ; sinon, la programme passe au bloc d'instructions sous else.
Pour lier plusieurs conditions, on utilise les opérateurs booléens.
Syntaxe de la commande
Remarque :
Il existe également une version négative du
Cette boucle permet de parcourir une table. A chaque tour de boucle, l'élément de la liste est affecté à la variable $var.
Syntaxe de la commande
Cette boucle permet d'appliquer des instructions tant que la/les condition(s) est/sont respectée(s), c’est-à-dire tant qu’elle(s) retourne(nt) la valeur « Vrai ».
Syntaxe de la commande
ferme le fichier correspondant au descripteur (ici, FIC, c'est-à-dire le nom donné au fichier lors de son ouverture pour pouvoir manipuler son contenu). Pour les dossiers, on utilisera
Cette commande, qui provient du module Encode, permet le décodage d'une chaîne de caractères.
Cette commande, qui provient du module HTML::Entities, permet le remplacement des entités HTML dans une chaîne de caractères par leur point de code en ISO-8859-1 correspondant.
Cette commande retourne une valeur positive si la valeur de la variable (ou la fonction &funct) est définie.
utilisée comme cas échéant avec une autre commande, elle permet de stopper l'exécution du script si l'autre commande a rencontré une erreur (ou de passer à la suite si une partie du code ne nécessite pas le résultat de la commande).
Il est préférable de commenter la fonction pour que l'utilisateur sache quelle commande a rencontré des problèmes, et y indiquer $! permet d'afficher les erreurs.
intercepte les exceptions et gère les erreurs qui en sont liées.
permet de mettre fin au programme.
Cette commande provient du module LWP::Simple et permet d'aspirer le contenu des pages Web en le stockant sur le disque local (à la manière de
retourne la longueur en caractères de la valeur de $var.
Cette commande, qui provient du module File::Path, permet de créer une arborescence par récursivité (il n'est plus nécessaire de préciser chaque chemin pour chaque sous-dossier, comme avec la commande
Exemple :
permet de déclarer les variables locales.
permet de passer à la prochaine itération de la boucle.
permet d'ouvrir les fichiers (en écriture "<", en écriture avec concaténation "<<" en lecture ">"). $fichier contient le chemin du fichier et associe son contenu à FIC (descripteur).
Pour les dossiers, on utilisera
print
(FIC) "contenu" :
Cette commande permet d'afficher le contenu se trouvant entre guillemets (dans un fichier en sortie lorsque l'on utilise son descripteur ; sinon dans l'invite de commande).
retourne la valeur résultante d'une fonction (on parle de fonction, et non de procédure, lorsque cette dernière renvoie une valeur).
Cette commande, qui provient du module File::Path, permet de supprimer une arborescence de dossiers en ne précisant seulement le chemin du dossier supérieur.
Cette commande permet d'introduire des fonctions (ou procédures, sous-routines), qui sont des blocs de code appelés dans un autre endroit du script (pour des raisons de lisibilité, on les place générallement à la fin du script).
extrait une sous-chaîne de caractères d'une chaîne de caractères.
Cette commande prend en compte 4 paramètres (les deux derniers sont facultatifs) :
- la chaîne de laquelle il faut extraire la sous-chaîne,
- la position du premier caractère de la sous-chaîne (! attention ! la numérotation commence à zéro),
- le nombre de caractères que doit comprendre la sous-chaîne,
- une chaîne de caractères de remplacement.
Cette commande permet de déclarer et d'importer les modules utilisés dans le script.
Cette commande sert à tester si un fichier respecte certaines propriétés (selon la lettre utilisée), et retourne en général la valeur 1 ou nulle.
Pour plus de précisions sur le fonctionnement des commandes...
Le résultat n'est pas tout à fait à la hauteur de nos attentes, mais nous attendons avec impatience le prochain projet pour nous améliorer !
Vous trouverez ci-dessous une petite description, non exhaustive, de quelques notions liées à la syntaxe de Perl et aux commandes utilisées dans le script.
Embûches :
Nous avons connu plusieurs difficultés lors de la réalisation de ce script :Nous nous sommes alors rabattus sur une solution plutôt ‘basique’, la seule qui voulait bien fonctionner sans faire trop d’erreurs : une condition ‘if’ était placée hors de la boucle 'while' afin que le programme informe l’utilisateur (en ajoutant une ligne à la fin du fichier contexte) s’il avait rencontré le motif non désiré dans le contexte déjà créé (code de la solution de secours et exemple de résultat).
Néanmoins, cette solution basique n’a pas été suffisante : pour des raisons qui nous échappent, le traitement bloquait pour certaines URLs et le programme ne pouvait donc poursuivre le parcours et le traitement des urls suivantes.
Finalement, n’ayant aucune autre solution en vue, nous nous sommes vus contraints d’abandonner cette idée… c’est bien dommage.
Après maintes tentatives, toutes autant inefficaces les unes que les autres, nous nous sommes résolus (encore une fois!) à abandonner leur traitement.
______________________________________________________________
Perl : Kézako ?
Perl (Practical Extraction and Report Language) est un langage de programmation créé par Larry Wall en 1987 pour la manipulation automatique de textes (comme son nom l’indique, même si l’acronyme a été forgé à postériori). C’est un langage qui, comme bash, est interprété et pré-compilé lors de son exécution.Perl présente plusieurs caractéristiques :
Pour en savoir plus...
NB :
Il existe toujours plusieurs façons de réaliser une même opération, d’où l’une des devises « Perl : la tronçonneuse suisse des langages de programmation (TIMTOWTDI) » qui lui est associée._______________________
Les variables en Perl
Il existe trois types de variables en perl dont les deux suivantes (utilisées dans le script), qui peuvent prendre comme valeur différents types de données :
les variables scalaires
$cdc = "chainedecaractères"
$nb = nombre
$var = $variable
les listes (ou tableaux)
@nom_tab=('toto',"$var",3)
! Attention ! Une chaîne de caractères encadrée par des apostrophes s’affiche telle qu’elle a été saisie (elle n'est pas interprétée par Perl, contrairement au contenu des guillemets doubles).
$var = "toto";
Remarque sur la portée des variables : une variable perl est par défaut 'globale', visible dans l'ensemble du code (c'est-à-dire accessible telle quelle, avec la même valeur assignée une seule fois).
Lorsque l'on veut restreindre la visibilité d'une variable à un bloc d'instructions (et rendre ainsi la variable 'locale'), on utilise la fonction
my
lors de l'assignation d'une valeur à la variable dans ce même bloc (pour cela, on utilise la directive "use
locale;" en début de script).On peut par la suite modifier sa valeur sans utiliser
my
(au sein du bloc d'instructions)._________
Il existe également des variables par défaut, très pratiques du point de vue de la concision et de la lisibilité du script : while
, $_ prendra comme valeur de la ligne courante).Elle peut également s'utiliser de manière implicite (sans être mentionnée)
Comme $_, elle peut s'utiliser de manière implicite
sub
).eval
() qui a été exécuté.Si $@ est vide, cela signifie que le dernier
eval
() a été évalué et exécuté correctement.die
qui a été exécuté.(vide lorsque l'instruction précédant
die
s'est déroulée correctement).Exemple : dans $motif=~ (directions?|\\w*-ways?|ways?), $1 a pour valeur "direction", "directions", "-way", "-ways", "way" ou "ways".
$` aura pour valeur la partie de la chaîne qui est avant ce qui a été reconnu,
$& aura pour valeur la partie de la chaîne qui a été reconnue,
et $' aura pour valeur la partie de la chaîne qui est après ce qui a été reconnu.
_______________________
Quelques opérateurs
=
: permet l'assignation d'une valeur à une variable.
: permet la concaténation de chaînesRemarque : pour la concaténation des valeurs que peut prendre une même variable, on utilise $var
.=
$var .==
: comparateur d'égalité!=
: comparateur d'inégalitéeq
: comparateur d'égaliténe
: comparateur d'inégalité&&
ouAND
: signifie "et"||
ouOR
: signifie "ou"!
ouNOT
: négation_______________________
Quelques structures de contrôle
if
:Comme tout langage de programmation, Perl possède une structure conditionnelle.
Elle permet de conditionner l'exécution d'instructions : si la condition est vérifiée, le bloc d'instructions (els)if sera exécuté ; sinon, la programme passe au bloc d'instructions sous else.
Pour lier plusieurs conditions, on utilise les opérateurs booléens.
Syntaxe de la commande
if
( condition(s) ) { liste d'instruction(s); }elsif
( autre(s) condition(s) ) { liste d'instruction(s); }else
{ liste d'instruction(s); }Remarque :
Il existe également une version négative du
if
:if
( !condition(s) ) =>unless
( condition(s) ) { instruction(s) }foreach
:Cette boucle permet de parcourir une table. A chaque tour de boucle, l'élément de la liste est affecté à la variable $var.
Syntaxe de la commande
foreach
$élément (@liste) { liste d'instructions; }while
:Cette boucle permet d'appliquer des instructions tant que la/les condition(s) est/sont respectée(s), c’est-à-dire tant qu’elle(s) retourne(nt) la valeur « Vrai ».
Syntaxe de la commande
while
( condition(s) ) { liste d'instruction(s); }_______________________
Quelques commandes
NB :
il peut exister d'autres syntaxes pour une même commande, et si une variable n'est pas précisée dans une instruction, cette dernière s'applique générallement à $_.close
( FIC ) :ferme le fichier correspondant au descripteur (ici, FIC, c'est-à-dire le nom donné au fichier lors de son ouverture pour pouvoir manipuler son contenu). Pour les dossiers, on utilisera
closedir
( DOS ).decode
( $var ) :Cette commande, qui provient du module Encode, permet le décodage d'une chaîne de caractères.
decode_entities
( $cdc ) :Cette commande, qui provient du module HTML::Entities, permet le remplacement des entités HTML dans une chaîne de caractères par leur point de code en ISO-8859-1 correspondant.
defined
( $var ) :Cette commande retourne une valeur positive si la valeur de la variable (ou la fonction &funct) est définie.
die
"commentaire" :utilisée comme cas échéant avec une autre commande, elle permet de stopper l'exécution du script si l'autre commande a rencontré une erreur (ou de passer à la suite si une partie du code ne nécessite pas le résultat de la commande).
Il est préférable de commenter la fonction pour que l'utilisateur sache quelle commande a rencontré des problèmes, et y indiquer $! permet d'afficher les erreurs.
eval
{ liste d'instruction(s); }:intercepte les exceptions et gère les erreurs qui en sont liées.
exit
:permet de mettre fin au programme.
get
( $url ) :Cette commande provient du module LWP::Simple et permet d'aspirer le contenu des pages Web en le stockant sur le disque local (à la manière de
wget
sous bash).length
( $var ) :retourne la longueur en caractères de la valeur de $var.
mkpath
"chemin" :Cette commande, qui provient du module File::Path, permet de créer une arborescence par récursivité (il n'est plus nécessaire de préciser chaque chemin pour chaque sous-dossier, comme avec la commande
mkdir
servant sous Perl et sous bash).Exemple :
my
$var :permet de déclarer les variables locales.
next
:permet de passer à la prochaine itération de la boucle.
open
(FIC,$fichier) :permet d'ouvrir les fichiers (en écriture "<", en écriture avec concaténation "<<" en lecture ">"). $fichier contient le chemin du fichier et associe son contenu à FIC (descripteur).
Pour les dossiers, on utilisera
opendir
(DOS,$dossier), dont le contenu sera lu à l'aide de la commandereaddir
(DOS).Cette commande permet d'afficher le contenu se trouvant entre guillemets (dans un fichier en sortie lorsque l'on utilise son descripteur ; sinon dans l'invite de commande).
return
$var :retourne la valeur résultante d'une fonction (on parle de fonction, et non de procédure, lorsque cette dernière renvoie une valeur).
rmtree
"chemin" :Cette commande, qui provient du module File::Path, permet de supprimer une arborescence de dossiers en ne précisant seulement le chemin du dossier supérieur.
sub
nom_fonction { instruction(s) } :Cette commande permet d'introduire des fonctions (ou procédures, sous-routines), qui sont des blocs de code appelés dans un autre endroit du script (pour des raisons de lisibilité, on les place générallement à la fin du script).
substr
( $cdc, i, j, $cdc_de_remplacement ) :extrait une sous-chaîne de caractères d'une chaîne de caractères.
Cette commande prend en compte 4 paramètres (les deux derniers sont facultatifs) :
- la chaîne de laquelle il faut extraire la sous-chaîne,
- la position du premier caractère de la sous-chaîne (! attention ! la numérotation commence à zéro),
- le nombre de caractères que doit comprendre la sous-chaîne,
- une chaîne de caractères de remplacement.
use
nom::module :Cette commande permet de déclarer et d'importer les modules utilisés dans le script.
-X
DESCRIPTEUR ou $fichier :Cette commande sert à tester si un fichier respecte certaines propriétés (selon la lettre utilisée), et retourne en général la valeur 1 ou nulle.
-X
peut prendre l'une des formes suivantes :-f
: Le fichier est un fichier normal.-d
: Le fichier est un répertoire.-z
: Le fichier a une taille nulle.-s
: Le fichier n'a pas une taille nulle (retourne sa taille en octets).Pour plus de précisions sur le fonctionnement des commandes...
______________________________________________________________
Script
Cliquer ici pour visualiser le script.______________________________________________________________