Le langage Perl, aujourd'hui dans sa version
5, est devenu particulièrement populaire auprès des auteurs de scripts
CGI (Common Gateway Interface). Gratuit, relativement facile d'accès
(surtout pour les familiers du monde Unix), il s'agit d'un langage
interprété, qui permet donc, en s'affranchissant d'une étape intermédiaire
de compilation, de gagner du temps lors des tests des programmes.
Cet article s'adresse à ceux qui, inexpérimentés en Perl, en possèdent
toutefois quelques bases, ou, à défaut, ont un peu l'expérience
de la programmation shell (ou d'autres langages). Ainsi, comprendre
la notion d'« expression régulière »
facilitera grandement leur tâche.
Le moteur de recherche viendra lire le contenu des fichiers d'un
répertoire, y rechercher un ou plusieurs mots-clés (sans opération
booléenne, l'opérateur OR étant implicite), en distinguant les majuscules
des minuscules, et sans classer les réponses : le programme
Perl devra récupérer les données d'un formulaire HTML et le contenu
des fichiers dans lesquels chercher, les traiter, puis renvoyer
les résultats sous forme d'une autre page HTML.
Récupération des données du formulaire
Supposons que l'attribut METHOD de la balise <FORM>
de votre formulaire HTML ait la valeur "GET", alors le
contenu de la variable d'environnement CGI $ENV{'QUERY_STRING'}
sera, par exemple, "keywords=journal+du+net&case=oui",
si les deux champs du formulaire ont pour noms keywords et case
(distinction majuscules/minuscules), et pour valeurs respectives
"journal du net" et "oui". Il faut alors extraire
de cette variable des informations utilisables :
@paires = split(/&/, $ENV{'QUERY_STRING'});
foreach $paire (@paires) {
($nom, $valeur) = split(/=/, $paire);
$valeur =~ s/\+/ /g;
$FORM{$nom} = $valeur;
}
L'observation de ces quelques lignes de code Perl permet d'apprendre
beaucoup sur la syntaxe du langage : variables, tableaux, appels
de fonction, boucles, etc. D'abord, on isole les différentes paires
nom/valeur en « découpant » (fonction split) la variable
d'environnement $ENV{'QUERY_STRING'} en autant de variables (stockées
dans le tableau @paires) qu'elle contient de caractères « & »
(+1) ; puis chaque paire ainsi obtenue est à son tour « découpée »
en deux variables : $nom et $valeur (le signe « = »
servant cette fois de séparateur). Un tableau associatif %FORM (dont
l'accès à une entrée s'effectue par $FORM{$nom}), vient enfin stocker
ces données de manière liée.
Attardons-nous sur l'instruction :
$valeur =~ s/\+/ /g;
Les familiers de sed ou awk, sous Unix, ne seront pas surpris par
cette notation : « $ch =~ s/A/B/ » signifie « remplacer
le premier caractère A de la chaîne $ch par le caractère B ».
Dans notre programme, A est le caractère « + » (\ est
nécessaire car + est un métacaractère), B est le caractère espace :
le suffixe g indique que toutes les occurrences de « + »,
et non plus seulement la première, doivent être remplacées (ici,
en l'occurrence, par un espace).
Récupération du contenu des fichiers
dans lesquels chercher
Supposons maintenant que vos pages HTML soient situées dans
le répertoire $rep : la fonction chdir permet de s'y
positionner. Supposons de plus qu'il s'agisse d'un serveur Unix :
l'instruction `ls *.html` (à ne pas confondre avec 'ls *.html' !)
renverra une variable qui contient tous les fichiers HTML du répertoire,
variable à partir de laquelle on récupère (à l'aide, une nouvelle
fois, de la fonction split), chaque nom de fichier dans un tableau.
Le métacaractère \s+ désignant à la fois les caractères espace,
« . » et « , », répétés une ou plusieurs fois.
chdir($rep);
$ls = `ls *.html`;
@fichiers = split(/\s+/, $ls);
Traitement des données
Vient alors l'étape de recherche : il est d'abord nécessaire
d'isoler chaque mot clé en « découpant » (fonction split)
la variable $FORM{'keywords'} définie plus haut.
@keywords = split(/\s+/, $FORM{'keywords'});
Il reste alors à ouvrir chaque fichier (fonction open), récupérer
chaque ligne dans un tableau (@lignes = <fichier>), refermer
le fichier (fonction close), concaténer toutes les lignes en une
seule chaine (fonction join), éliminer de cette variable ($chaine)
les caractères de fin de ligne (métacaractère \n), puis effectuer
la recherche proprement dite.
foreach $fichier (@fichiers) {
open(fichier, "$fichier");
@lignes = <fichier>;
close(fichier);
$chaine = join('.', @lignes);
$chaine =~ s/\n//g;
# Recherche
#
}
La boucle de recherche est construite sur le modèle suivant :
foreach $keyword (@keywords) {
If ($chaine =~ /$keyword/i) {
$INCLURE{$fichier}='oui';
}
else {
$INCLURE{$fichier}='non';
}
if ($chaine =~ /<title>(.*)<\title>/i) {
$TITRE{$fichier} = "$1";
}
else {
$TITRE{$fichier} = "$fichier";
}
}
La notation « $ch =~ /$A/i » signifiant « comparer la
variable $A à la variable $ch sans tenir compte des majuscules ou
des minuscules (suffixe i) ». Si $A est contenue dans $ch,
l'instruction renverra la valeur logique « vrai ».
Ainsi, après avoir décidé si le fichier doit être inclus ou non
dans la liste des résultats, on stocke cette information ainsi que
le titre de la page web correspondante dans deux tableaux associatifs.
Si la page n'a pas de titre défini entre les balises <TITLE>
et </TITLE>, on lui donne comme titre le nom du fichier. A
noter que la variable $1 correspond à la chaine de caractère récupérée
avec le symbole (métacaractère) (.*).
Il reste à distinguer le cas d'une recherche en faisant la distinction
majuscules/minuscules du cas d'une recherche sans distinction :
le second correspond à ce qui vient d'être fait, le premier se programme
en supprimant le suffixe i à l'instruction de comparaison. La boucle
de recherche devient :
foreach $keyword (@keywords) {
if ($FORM{'case'} eq 'oui') {
if ($chaine =~ /$keyword/) {
$INCLURE{$fichier}='oui';
}
else {
$INCLURE{$fichier}='non';
}
elsif ($FORM{'case'} eq 'non') {
If ($chaine =~ /$keyword/i) {
$INCLURE{$fichier}='oui';
}
else {
$INCLURE{$fichier}='non';
}
}
if ($chaine =~ /<title>(.*)<\title>/i) {
$TITRE{$fichier} = "$1";
}
else {
$TITRE{$fichier} = "$fichier";
}
}
Affichage des résultats
L'affichage des résultats sous forme de pages web est la
dernière étape : le Perl permet d'écrire du code HTML avec
l'instruction print. Ainsi par exemple :
print "<a href=\"http://www.journaldunet.com\">Lien</a>\n";
écrit le code HTML:
<a href="http://www.journaldunet.com">Lien</a>
puis passe à la ligne (caractère \n). Les guillemets étant des
caractères réservés, on les fait précéder, dans l'instruction Perl,
d'un \ pour éviter la confusion.
Pour afficher les résultats, on écrira en particulier (si $url
contient l'URL du répertoire dans lequel la recherche a eu lieu) :
foreach $resultat (%INCLURE) {
if ($INCLURE{$resultat} eq 'oui') {
print "<a href=\"$url$resultat\">$TITRE{$resultat}</a>\n";
}
}
Le code complet (fonctionnant sous serveur Unix) de ce mini-moteur
de recherche peut être . De nombreuses autres fonctionnalités
peuvent être ajoutées à ce programme, comme la gestion des
opérateurs booléens ou la possibilité de rechercher une phrase
entière. Une meilleure gestion des fichiers (parcours récursifs
dans les répertoires, fichiers cherchés non limités aux fichiers
HTML), et un meilleur traitement des données du formulaire
seraient également pertinents. L'architecture du programme
bénéficiera aussi d'un découpage en sous-routines. Ces ajouts
ne sont, individuellement, pas difficiles et constituent un
bon moyen de progresser en Perl.
Pour plus de renseignements, la source d'information la plus riche
reste la documentation
Perl.
|