|
Télécharger
le .dir correspondant à cette étape |
Analyse d'un corpus de texte sur le disque dur. Attention,
ci-contre, ce n'est pas l'animation shockwave mais une
simple capture d'écran. En effet, cette application utilise un
Xtra qui ne fonctionne pas sous shockwave. Ce qui du reste se comprend,
nous expliciterons cela au moment de nous servir de cet Xtra. Pour cette dernière étape, nous allons abandonner quelques unes des fonctions que nous avions développées jusque là. Nous n'allons plus faire d'analyse d'occurrences, ni continuer à choisir un critère de tri, ni un ordre de classement. En effet, cette neuvième étape en forme de conclusion va uniquement consister à faire une recherche de sous-chaîne dans un texte, telle que nous l'avons construite aux étapes 4 et 5 de cet exercice. Mais cette fois, le texte source dans lequel nous allons chercher ne sera plus un texte unique contenu dans un acteur champ, mais un ensemble de textes différents situés à l'extérieur de l'animation, c'est à dire que ces textes existent sous forme de différents fichiers ASCII présents sur le disque dur. Une fois que notre animation aura indiqué le nom
des fichiers qui comportent la sous-chaîne recherchée dans
la fenêtre de résultat, les noms de ces fichiers pourront
se mettre en surbrillance (et uniquement les noms de fichiers, pas les
autres mots de la fenêtre de résultat). Un clic sur le nom
de fichier alors en surbrillance provoquera l'affichage du texte correspondant
dans la fenêtre de texte (au dessus), et les occurrences seront mise
en rouge et en gras, comme nous l'avions fait aux quatrième et
cinquième étapes. |
Le corpus comprend
15 textes mais rien ne vous empêche d'en ajouter.
A l'exception de voltaire.txt, dont la version sous forme de fichier provient
d'une source inconnue, toutes les autres versions électroniques de ces
textes proviennent de l'ABU (http://abu.cnam.fr/).
Voici quels sont
ces textes et d'où ils sont tirés :
- balzac.txt : début de "L'élixir de
longue vie",
- diderot.txt : début des "Pensées sur
l'interprétation de la nature",
- dumas.txt : début de "Les Trois Mousquetaires",
- flaubert.txt : début de "Madame Bovary",
- hugo.txt : début de "La fin de Satan",
- laclos.txt : une lettre du viconte de Valmont à la
marquise de Merteuil, au début des "Liaisons dangereuses",
- loti.txt : un eXtrait au début d’ "Aziyadé",
- merimee.txt : début de "Colomba",
- pascal.txt : début de "Petits écrits
philosophiques et religieux ",
- plutarque.txt : début du Livre premier de "Des
opinions des philosophes",
- rousseau.txt : début des "Confessions",
- stendhal.txt : un eXtrait au début de "La
Chartreuse de Parme",
- verne.txt : un eXtrait au début de "De la
Terre à la Lune",
- volataire.txt : début du pamphlet "L'affaire
Calas",
- zola.txt : début de "L’argent".
Du fait que Lingo ne sait pas, de manière native, accéder
au disque dur ni au système, il nous faut utiliser des extensions du
langage qu'on appelle des Xtras. Ces Xtras sont en fait des modules (on dirait
des plug-ins dans la terminologie des navigateurs web), qui apportent
un jeu d'instructions supplémentaires au lingo de base. Ce jeu d'instructions
est en général spécialisé sur un thème particulier
: on peut trouver des Xtras pour des fonctionnalités 3D, pour le son
et la musique, pour la capture et le traitement de vidéo, pour accéder
aux fonctions du système d'exploitation, pour l'accès aux bases
de données... Il en existe une multitude.
Certains, très basiques, ont été développés
directement par Macromedia ou un de ses partenaires, et sont livrés en
standard avec Director (pour être plus exact, beaucoup d'enrichissements
à Lingo à travers ses versions successives ont été
faits par l'adjonction d'Xtras livrés en standard, et dont l'initialisation
est transparente pour l'utilisateur).
D'autres, plus spécialisés, ont été développés
par des tierces parties (on appelle ainsi des développeurs qui travaillent
pour les produits d'un constructeur mais sans faire partie de ce constructeur).
Ces Xtras sont payants, ce sont des produits commerciaux, et leur prix peut
aller de quelques dizaines à plusieurs milliers de dollars. Une fois
installés, il doivent être enregistrés en général
à l'aide d'un numéro de série ou d'une clé d'activation
fournis par le développeur de l'Xtra une fois la license de celui-ci
achetée.
Ces Xtras peuvent faire partie de diverses catégories.
On peut citer :
- les "Asset Xtras" qui en général s'importent dans
une animation Director sous la forme d'un acteur, lequel est doté de
méthodes et de propriétés propres à l'Xtra (un exemple
d'Asset Xtra : videoSprite).
- les "scripting Xtras" qui sont des modules de code qui après
instanciation, permettront d'accéder depuis les scripts lingo à
leur jeu d'instructions et à leurs propriétés.
Que ce soient des "Asset Xtras" ou des "scripting
Xtras", les propriétés et méthodes qui leurs sont
attachées sont documentées par le développeur de l'Xtra.
Cette doccumentation est plus ou moins bien faite, et il peut arriver qu'on
soit obligé d' "inventer" ou de supposer quand la documentation
est vraiment indigente (il n'y a alors pas d'autre solution que de faire l'essai
de probables commandes sous diverses syntaxes habituelles et avec divers paramètres
jusqu'à ce que l'on trouve ce qui marche. C'est long et monotone, et
cela suppose une bonne connaissance des langages en général ainsi
que des conventions les plus répandues pour deviner les commandes possibles).
Dans cette étape, nous utiliserons deux scripting Xtras,
lesquels permettent :
- pour l'un, de lire un fichier ASCII sur le disque. Cet Xtra s'appelle FileIO.
S'il n'est pas présent dans votre dossier Xtra du répertoire d'installation
de Director, vous devez le télécharger (voir ci-dessus l'introduction
de cette étape),
- pour l'autre, pour pouvoir connaître la structure du disque dur, et
récupérer les noms des volumes et fichiers qui s'y trouvent. Cet
Xtra s'appelle fileXtra4.S'il
n'est pas présent dans votre dossier Xtra du répertoire d'installation
de Director, vous devez le télécharger (voir ci-dessus l'introduction
de cette étape).
Compte tenu de tout ce qui précède, le .dir de cette étape a été débarassé de quelques éléments et scripts qui ne sont plus utilisés ici. Néanmoins, il est tout à fait possible, en adaptant l'interface et les scripts, de réimplémenter les statistiques du texte et les analyses d'occurrences pour le texte qui aurait été choisi dans la liste des fichiers présentée par l'application.
Voici la description du fonctionnement de cette étape
:
- un ensemble de textes (15 dans l'exercice) est présent sur le disque
dur dans un sous dossier de l'application ,
- un champ "cherche" (comme aux quatrième et cinquième
étapes de l'exercice) permet de saisir une chaîne de caractères
à rechercher,
- un bouton permet de lancer la recherche sur l'ensemble des fichiers textes,
sans pour autant les afficher,
- une fois la recherche terminée, le champ "résultat"
indique le nombre de fichiers contenant la sous-chaîne recherchée
avec rappel de cette sous-chaîne, et au dessous, donne la liste de ces
fichiers, avec le nombre d'occurrences de la sous-chaîne cherchée
que chacun d'eux contient,
- le nom de chaque fichier se met en surbrillance au passage de la souris, et
un clic sur ce nom de fichier provoque son affichage dans le champ "leTexte",
affichage dans lequel chaque occurrence de la sous-chaîne recherchée
est mise en rouge et en gras, comme précédemment
,
- on a conservé l'option de limiter la recherche aux mots entiers.
Au démarrage de l'application, on trouvera relativement peu de changement dans le prepareMovie. Les différents champs sont remis à vide, leur affichage est réinitialisé en noir et en style normal. Le timeOut existe toujours puisque nous avons toujours des ascenseurs.
La différence réside surtout dans le fait de créer
l'instance de l'Xtra fileIO et l'instance de l'Xtra fileXtra4.
S'agissant de "scripting Xtras", il faut en créer une instance
à laquelle on s'adressera ensuite pour réaliser les fonctions
que nous souhaitons.
Cela se fait toujours de la même façon : l'instance étant
un objet, il faut une variable globale (globale parce qu'elle devra être
accessible depuis d'autres scripts) pour l'héberger, exactement comme
nous avons une globale qui héberge le timeOut.
Une fois les globales déclarées (ici appelées leFichier
et leFx), il suffit de les affecter en utilisant la
méthode new() des l'Xtra (ceci est valable pour presque tous
les scripting Xtras).
Et on écrira : leFichier = new(Xtra "fileIO")
et leFx = new(xtra "fileXtra4")
S'agissant d'Xtras livré en standard ou gratuits, il n'est pas nécessaire
de leur appliquer une méthode d'enregistrement ou d'autorisation avec
un numéro de série. D'autre part, ces Xtra ne réclament
pas non plus de méthode d'initialisation (comme par exemple pour l'Xtra
permettant de communiquer avec les ports de la machine, où il faut indiquer
non seulement le nom du port que l'on désire attaquer, mais encore donner
quelques éléments de protocole).
Pour une bizarre raison, sur laquelle je n'ai aucune explication
et n'ai trouvé aucun article sur internet, si les instances d'Xtra sont
créées en tête du prepareMovie, alors toutes les
instructions qui suivent sont ignorées, et dans le cas présent
les éléments qui devraient être cachés par la mise
à 0 de leur propriété visible, ne le sont pas.
Ils le sont correctement dans l'environnement de développement, mais
plus dans les projections ni dans les Shockwave !
C'est pour cette raison que les instance d'Xtra FileIO et fileXtra4
sont créées à la fin du prepareMovie.
Il nous faut également créer une autre globale pour y inscrire
les noms des fichiers qui composent le corpus de textes, de manière à
pouvoir accéder à ces fichiers depuis d'autres scripts. Cette
globale, appelée lstFichiers dans l'exercice,
est initialisée comme une liste vide dans le prepareMovie. Elle
sera peuplée dans le mouseUp du bouton.
Nous aurions pu la peupler tout de suite dans le prepareMovie, mais
alors, si jamais nous voulions utiliser notre application sur un répertoire
dont le contenu peut changer dans le temps, et sans redémarrer notre
application, nous n'aurions pas de remise à jour du contenu du répertoire,
puisque la liste aurait été fixée une fois pour toutes
au démarrage (le prepareMovie est un événement
système unique et instantané).
Enfin, dernier mot à propos des scripting Xtras : quand
on en a créé une instance, il faut, pour éviter tout conflit
ultérieur, la détruire quand on quitte l'animation. On a donc
rajouté un gestionnaire on stopMovie (événement
système unique se produisant lorsqu'on sort de l'application), dans lequel
on met les globales leFichier et leFx à 0, ce qui détruit
les instances d'Xtra.
On a également rajouté une ligne clearGlobals,
que l'on devrait toujours écrire : cette instruction détruit toutes
les globales. On est ainsi sûr de ne pas conserver de valeurs indésirables
à la sortie de l'application. Ceci est surtout valable en phase de développement.
Donc les scripts d'animation se présentent comme suit
(on rajoute également des instructions pour cacher les sprite 41 à
43 ; nous verrons plus loin à quoi cela correspond) :
global t, leFichier, lstFichiers, leFx
on prepareMovie
t
= timeout("g").new(250, #moteur)
on stopMovie
leFichier
= 0
leFx
= 0
clearGlobals
end
Il n'y a dans tout cela aucune difficulté.
Puis nous allons modifier le script du bouton de recherche.
Tout d'abord, il faut rappeler la déclaration des globales
leFichier et leFx (instances d'Xtra), et lstFichiers (les
fichiers qui composent le corpus), qui vont maintenant nous servir.
Les propriétés du sprite ne changent pas, non plus que son beginSprite
et ses mouseEnter et Leave.
La fonction chercherTexte(uneChaîne, unTexte)
change très peu. On l'a simplement amputée de la section qui élaborait
et affichait le message de résultat. En effet, ce n'est plus le même
message que nous allons afficher (puisque dorénavant nous allons afficher
une liste de fichiers). Nous avons remonté cette fonctionnalité
dans le mouseUp.
Seule chose : puisque pour élaborer le message, le mouseUp aura
besoin des trouvailles calculées par chercherTexte(uneChaîne,
unTexte), nous avons rajouté à chercherTexte() une
instruction return qui lui impose de renvoyer ce qu'elle a trouvé.
chercherTexte(uneChaîne, unTexte) se présente donc désormais
sous cette forme :
on chercherTexte(uneChaîne, unTexte) me
nbCaract
= uneChaîne.length
nbCharTotal
= unTexte.length
lstTrouvailles
= []
repeat
with i = 1 to nbCharTotal - (nbCAract - 1)
![]()
aComparer
= ""
![]()
repeat
with j = 1 to nbCaract
![]()
![]()
aComparer
= aComparer&(char(i+(j-1)) of unTexte)
![]()
end
repeat
![]()
if
aComparer = uneChaîne then
![]()
![]()
if
motEntier = 1 then
![]()
![]()
![]()
leCharAvant
= unTexte.char[i - 1]
![]()
![]()
![]()
leCharApres
= unTexte.char[i + nbCaract]
![]()
![]()
![]()
if
lstDelimiteurs.getPos(leCharAvant) <> 0 and lstDelimiteurs.getPos(leCharApres)
<> 0 then
![]()
![]()
![]()
![]()
lstTrouvailles.add(i)
![]()
![]()
![]()
end
if
![]()
![]()
else
![]()
![]()
![]()
lstTrouvailles.add(i)
![]()
![]()
end
if
![]()
end
if
end
repeat
return
lstTrouvailles
end
C'est le mouseUp qui va subir la plus grande refonte
:
- pour pouvoir, à la fin du mouseUp, afficher les noms des fichiers
qui contiennent la sous-chaîne recherchée, et comme nous examinerons
l'ensemble des fichiers en séquence, nous allons avoir besoin d'une liste
pour marquer les fichiers qui correspondent à la recherche. Et comme
nous indiquons, dans le résultat, le nombre d'occurrences de la sous-chaîne
recherchée que contient chaque fichier, cette liste sera une liste de
propriétés dont les couples seront [nomDeFichier:nombreDoccurrences].
Dans l'exercice, j'ai appelé cette liste lstFichiersQuiCorrespondent,
et elle est initialisée à vide au début du mouseUp.
- l'analyse de l'ensemble des fichiers durera un certain temps (comme "le
fût du canon..."), temps d'autant plus long que le nombre de fichiers
à analyser sera plus grand, comme on peut s'y attendre. Même avec
15 textes seulement, ce temps est largement perceptible. Il faut donc, pendant
l'analyse, indiquer à l'utilisateur de notre application, que la machine
n'est pas plantée mais qu'elle est en train de travailler. Ceci peut
se faire par un changement de curseur de souris, mais il est beaucoup plus élégant
de montrer aussi quel est l'état d'avancement du travail d'analyse, et
nous allons donc nous doter d'une barre de progression. Celle-ci se compose
de trois éléments (trois sprites sur la scène) : une légende
"Recherche en cours, veuillez patienter...", la barre de
progression proprement dite dont la longueur augmente à mesure que le
travail s'accomplit, et enfin un cadre, qui graphiquement délimite cette
barre, mais qui montre aussi, visuellement, quelle est la longueur totale de
la barre (atteinte quand le traitement d'analyse est terminé). Ce cadre
permet à l'utilisateur d'évaluer d'un coup d'œil la proportion
de travail déjà réalisé.
Ces trois éléments devront être cachés en temps normal
ainsi qu'au démarrage de l'application (et
c'est pour cela que nous avons caché les sprite 41 à 43 dans le
prepareMovie, les trois éléments de cette barre étant
posés sur ces sprites). Ils devront apparaître quand on
lance une recherche. Une fois la recherche terminée, ces trois éléments
sont cachés à nouveau et laissent la place à l'affichage
des résultats. Cette barre n'empèche pas de modifier le curseur
de la souris.
Pour faire varier la longueur de la barre pendant la recherche, on va modifier
la propriété right du sprite qui la contient. Faire varier
l'un des cotés d'un sprite (left, right, top
ou bottom) revient à modifier sa forme et à l'étirer
(ou le contracter) dans le sens correspondant au coté que l'on manipule.
Le pas de progression de la barre sera déterminé par le rapport
de sa longueur totale sur le nombre de fichiers à analyser, toujours
en faisant attention de rendre décimal l'un des opérandes du rapport
pour éviter la division entière. Je rappelle que cette conversion
se fait soit par une multiplication de l'un des opérandes par 1,0 ou
par l'utilisation de la fonction float(nombreAConvertir).
Voici pour l'interface.
Ensuite,
il nous faut constituer la liste des fichiers dans lesquels rechercher. Ceci
sera fait par un appel à l'instance de l'xtra fileXtra4, leFx,
et en lui appliquant sa méthode fx_FolderToList.
Cette méthode, construite dans l'Xtra, est indiquée par sa documentation
(téléchargeable au début de cette étape). Elle renvoie
une liste de tous les fichiers et sous-répertoire contenus dans le répertoire
indiqué comme chemin à la méthode (voir ci-dessous la propriété
the moviePath).
Puis, pour procéder à l'analyse des fichiers, nous allons, dans
une boucle de répétition, demander à l'Xtra fileIO
d'ouvrir chacun des fichiers du corpus, de stocker son contenu dans une variable,
et de faire la recherche dans ce texte. Nous ajouterons à la liste lstFichiersQuiCorrespondent,
en propriété le nom du fichier correspondant si chercherTexte()
y a trouvé une ou des occurrences de la sous-chaîne recherchée,
et en valeur, le nombre d'occurrences existant dans ce fichier.
Enfin, on élabore le message par concaténation de morceaux de
chaîne comme nous l'avons fait jusqu'ici, en balayant la liste lstFichiersQuiCorrespondent.
Nous prévoierons toutefois d'élaborer un message spécifique
différent :
- si la recherche est infructueuse et qu'aucune occurrence de la sous-chaîne
recherchée n'a été trouvée. C'est plus élégant
que d'annoncer "0 fichier comportent la sous chaîne...",
- selon le nombre de fichiers trouvés. Comme le résultat est exprimé
en français correct, le mot "fichier" et le verbe "comporte"
du message de résultat s'écrivent au singulier si on n'a trouvé
qu'un seul fichier correspondant à la recherche, et s'écrivent
au pluriel s'il y en a plusieurs.
Nous avons donc trois cas pour le message de résultat : aucun fichier,
un seul fichier, plusieurs fichiers.
L'élaboration du message sera donc écrite en conséquence
à l'aide d'instructions conditionnelles.
Avant d'écrire notre mouseUp en pseudo-code,
voyons quelles seront les instructions à donner à l'Xtra fileIO
pour extraire le texte contenu dans les fichiers. Le fonctionnement est simple
:
- il faut indiquer quel fichier ouvrir ainsi que le chemin pour y accéder.
Une instance de l'Xtra fileIO ne peut ouvrir qu'un seul fichier à
la fois. Si l'on souhaite ouvrir en même temps plusieurs fichiers (ce
qui n'est pas le cas ici), il faudra créer autant d'instances de l'Xtra
que de fichiers que l'on désire ouvrir à la fois.
- Avant de lire ou d'écrire dans un fichier, il faut ouvrir ce fichier.
L'ouverture peut se faire dans trois modes différents : en lecture/écriture
(on peut lire et écrire), en lecture seule (l'écriture est impossible),
en écriture seule (la lecture est impossible). L'instruction qui correspond,
et qui doit être appliquée comme une méthode de l'instance
d'Xtra, est la suivante : leFichier.openFile(chemin\nomFichier,
numeroDuMode), dans laquelle le numéro du mode vaut 0 en
lecture/écriture, 1 en lecture seule et 2 en écriture seule. Dans
notre exercice, afin de ne pas modifier le texte par erreur, nous ouvrirons
le fichier en lecture seule.
- l'Xtra possède des instructions pour lire le fichier entier d'un seul
coup, pour lire une ligne isolée (les lignes sont délimitées
par des retours chariot), ou pour lire un caractère isolé. Dans
le cas des lignes ou des caractères isolés, il faut savoir qu'il
existe dans les fichiers un pointeur qui désigne la position du caractère
sur lequel on se trouve. Il faut donc fixer la position du pointeur avant de
demander à l'Xtra de lire une ligne ou un caractère isolé.
Dans le cas d'une écriture, c'est la même chose, il faut fixer
la position du pointeur à l'endroit où on veut écrire le
caractère. Dans l'exercice, nous placerons ce pointeur sur la position
0, qui est située juste avant le premier caractère (*),
et nous utiliserons l'instruction leFichier.readFile(),
puisque nous cherchons à récupérer le fichier entier, c'est
à dire la totalité du texte (**).
- Enfin, après avoir lu le fichier, nous le refermons à l'aide
de l'instruction leFichier.closeFile().
Ce qui nous donne (en exagérant les retraits pour plus de clarté, et en mettant en couleur les blocs de codes) :
on mouseUp
si
l'acteur "cherche" n'est pas vide alors
![]()
![]()
peupler
la liste lstFichiers à l'aide de l'xtra fileXtra4
![]()
![]()
vider
l'acteur "leTexte"
![]()
![]()
vider
l'acteur "resultat"
![]()
![]()
initialiser
une liste de propriété vide appelée lstFichiersQuiCorrespondent
![]()
![]()
Rendre
visible la barre de progression, son cadre et sa légende
![]()
![]()
affecter
à la souris le curseur "machine occupée" (sablier ou
autre)
![]()
![]()
calculer
le pas de déplacement de la barre de progression : largeur intérieure
du cadre (ici 230) / nombre de fichiers à analyser
![]()
![]()
répéter
avec les noms de fichiers contenus dans la lstFichiers
![]()
![]()
![]()
![]()
déplacer
le coté droit de la barre de progression de la valeur d'un pas
![]()
![]()
![]()
![]()
rafraichir
la scène
![]()
![]()
![]()
![]()
ouvrir
le fichier dans le sous répertoire lesTextes en lecture seule
![]()
![]()
![]()
![]()
positionner
le pointeur du fichier à la position 0 (avant le premier caractère)
![]()
![]()
![]()
![]()
lire
le contenu du fichier et mettre ce contenu dans une variable leContenu
![]()
![]()
![]()
![]()
fermer
le fichier
![]()
![]()
![]()
![]()
lire
la sous-chaîne saisie dans l'acteur "cherche" et la stocker
dans une variable laChaine
![]()
![]()
![]()
![]()
appeler
la fonction chercherTexte en lui passant laChaine et leContenu en arguments,
et mettre le résultat (qui se présente sous forme de liste) dans
une variable appelée lesTrouvailles
![]()
![]()
![]()
![]()
Si
le nombre d'éléments de lesTrouvailles > 0 alors
![]()
![]()
![]()
![]()
![]()
![]()
ajouter
à lstFichiersQuiCorrespondent le nom du fichier et le nombre d'éléments
de lesTrouvailles (= nombre d'occurrences trouvées dans ce fichier)
![]()
![]()
![]()
![]()
fin
si
![]()
![]()
fin
répéter
![]()
![]()
cacher
la barre de progression, son cadre et sa légende
![]()
![]()
remettre
le bord droit de la barre de progression à sa position initiale (ici
108)
![]()
![]()
réaffecter
un curseur normal àl a souris
![]()
![]()
rafraîchir
la scène
![]()
![]()
si
le nombre d'éléments de lstFichiersQuiCorrespondent = 0 alors
![]()
![]()
![]()
![]()
leMessage
= "Aucun fichier ne contient la sous-chaîne" auquel on ajoute
un espace et des guillements puis le texte de l'acteur "cherche",
puis des guillemets à nouveau puis la chaine "recherchée"
![]()
![]()
sinon
si le nombre d'éléments de lstFichiersQuiCorrespondent = 1 alors
![]()
![]()
![]()
![]()
leMessage
= "Un seul fichier comporte la sous-chaîne" auquel on ajoute
un espace puis des guillemets puis le texte de l'acteur "cherche"
puis des guillemets à nouveau puisl a chaine "recherchée
: " suivie de deux sauts de ligne
![]()
![]()
![]()
![]()
extraire
le nom de la propriété de l'unique élément de lstFichiersQuiCorrespondent
et l'appeler fichierQuiVaBien
![]()
![]()
![]()
![]()
extraire
la valeur correspondant à cette propriété et l'appeler
lesoccurrences
![]()
![]()
![]()
![]()
leMessage
= leMessage auquel on ajoute fichierQuiVaBien puis un espace et la chaine "......(nombre
d'occurrences trouvées : " puis un espace, puis lesoccurrences puisla
chaine ")" pour fermer la paranthèse et enfin un saut de ligne
![]()
![]()
sinon
![]()
![]()
![]()
![]()
leMessage
= le nombre d'éléments de lstFichiersQuiCorrespondent et un espace
et la chaine "fichiers comportent la sous-chaîne" puis des guillemets
puisl e texte de l'acteur "cherche" puis des guillemets à nouveau
puis la chaine "recherchée : "puis deux sauts de ligne
![]()
![]()
![]()
![]()
répéter
avec un compteur i de 1 jusqu'au nombre d'éléments de la liste
lstFichiersQuiCorrespondent
![]()
![]()
![]()
![]()
![]()
![]()
extraire
le nom de fichier de rang i dans la liste lstFichiersQuiCorrespondent et le
stocker dans une variable appelée fichierQuiVaBien
![]()
![]()
![]()
![]()
![]()
![]()
extraire
la valeur associée à fichierQuiVaBien et la stocker dans une variable
appelée lesoccurrences
![]()
![]()
![]()
![]()
![]()
![]()
leMessage
= leMessage auquel on ajoute fichierQuiVaBien pui un espace, puis la chaine
"......(nombre d'occurrences trouvées : " puis un espace puis
lesoccurrences puis la chaine ")" pour fermer les paranthèses
puis un saut de ligne
![]()
![]()
![]()
![]()
fin
répéter
![]()
![]()
fin
si
![]()
![]()
afficher
le message dans l'acteur "resultat"
fin
si
end
Bien que ce script comporte beaucoup d'imbrications, il ne pose pas de difficulté.
On peut y faire quatre remarques avant d'implémenter
le code correspondant :
- le changement du curseur de souris : cette commande et ses variantes ont été
vues dans le deuxième exercices aux étapes 4 et 6. Je le rappelle
ici car la commande n'a pas été utilisée depuis dans ce
cours.
- Pour la création de la liste lstFichiers et l'ouverture du
fichier, on dit qu'il faut indiquer le chemin et le nom du fichier. Les fichiers
se trouvent dans un sous-répertoire "lesTextes" du répertoire
dans lequel se trouve l'animation. Il existe une propriété d'animation
qui indique le chemin du répertoire contenant l'animation. Cette propriété
s'appelle the moviePath.
Pour indiquer le chemin des fichiers textes, nous emploierons
donc, sous la forme d'une concaténation de chaine : (the
moviePath)&"lesTextes\" (ceci est la notation des
chemins sur les machines windows. Se reporter au dictionnaire lingo pour connaitre
les différentes syntaxes sur Mac).
- Pour balayer la liste des fichiers afin de les faire ouvrir en séquence
par fileIO, nous allons utiliser une variante des boucles de répétions,
variante qui n'est en fait utilisable qu'avec des listes. Cette forme est la
suivante : repeat with uneVariable in uneListe... ...end repeat.
Dans cette forme, le compteur habituel, que nous avons appelé
ici uneVariable, prend successivement toutes les valeurs des éléments
de la liste uneListe.
Dans l'exercice, on a écrit repeat with nomFichier in lstFichiers...
... end repeat. nomFichier contiendra successivement
tous les noms de fichiers contenus dans la liste.
- A l'intérieur de la boucle de répétition qui
balaye la liste des fichiers, on a inclus une instruction updateStage
pour rafraîchir la scène : quand on montre la barre de progression,
quand on modifie sa longueur à l'intérieur de la boucle de répétition,
et enfin une troisième après avoir caché à nouveau
les éléments de la barre de progression. Ces instructions sont
indispensables ici dans la mesure où on a besoin de voir les modifications
sur la scène aussitôt que la commande a été émise,
sans attendre un rafraîchissement automatique à la fin du mouseUp.
Si on supprime ces updateStage (et surtout celui qui est à l'intérieur
de la boucle de répétition), on ne verra pas apparaître
la barre de progression (elle aura été remise en invisible avant
qu'un rafraîchissement ait eu lieu).
Voici donc notre script une fois codé (et en respectant les mêmes couleurs pour les blocs que ci-dessus) :
on mouseUp
if
member("cherche").text <> "" then
![]()
![]()
lstFichiers
= leFx.fx_FolderToList((the moviePath)&"lesTextes")
![]()
![]()
member("leTexte").text
= ""
![]()
![]()
member("resultat").text
= ""
![]()
![]()
lstFichiersQuiCorrespondent
= [:]
![]()
![]()
sprite(41).visible
= 1
![]()
![]()
sprite(42).visible
= 1
![]()
![]()
sprite(43).visible
= 1
![]()
![]()
cursor
4
![]()
![]()
updateStage
![]()
![]()
pasBarre
= 230.0 / lstFichiers.count()
![]()
![]()
repeat
with nomFichier in lstFichiers
![]()
![]()
![]()
![]()
sprite(42).right
= sprite(42).right + pasBarre
![]()
![]()
![]()
![]()
updateStage
![]()
![]()
![]()
![]()
leFichier.openFile(the moviePath&"lesTextes"&"\"&nomFichier,
1)
![]()
![]()
![]()
![]()
leFichier.setPosition(0)
![]()
![]()
![]()
![]()
leContenu
= leFichier.readFile()
![]()
![]()
![]()
![]()
leFichier.closeFile()
![]()
![]()
![]()
![]()
laChaine
= member("cherche").text
![]()
![]()
![]()
![]()
lesTrouvailles
= chercherTexte(laChaine, leContenu)
![]()
![]()
![]()
if
lesTrouvailles.count > 0 then
![]()
![]()
![]()
![]()
![]()
![]()
lstFichiersQuiCorrespondent.addProp(nomFichier,
lesTrouvailles.count)
![]()
![]()
![]()
end
if
![]()
![]()
end
repeat
![]()
![]()
sprite(41).visible
= 0
![]()
![]()
sprite(42).visible
= 0
![]()
![]()
sprite(43).visible
= 0
![]()
![]()
sprite(42).right
= 108
![]()
![]()
cursor
-1
![]()
![]()
updateStage
![]()
![]()
if lstFichiersQuiCorrespondent.count = 0 then
![]()
![]()
![]()
![]()
leMessage
= "Aucun fichier ne contient la sous-chaîne"&"e&member("cherche").text"e&&"recherchée."
![]()
![]()
else
if lstFichiersQuiCorrespondent.count = 1 then
![]()
![]()
![]()
![]()
leMessage
= "Un seul fichier comporte la sous-chaîne"&"e&member("cherche").text"e&&"recherchée
: "&return&return
![]()
![]()
![]()
![]()
fichierQuivaBien
= lstFichiersQuiCorrespondent.getPropAt(1)
![]()
![]()
![]()
![]()
lesoccurrences
= lstFichiersQuiCorrespondent.getProp(fichierQuiVaBien)
![]()
![]()
![]()
![]()
leMessage
= leMessage&fichierQuivaBien&&"......(nombre d'occurrences trouvées
: "&&lesoccurrences&")"&return
![]()
![]()
else
![]()
![]()
![]()
![]()
leMessage
= lstFichiersQuiCorrespondent.count&&"fichiers comportent la sous-chaîne"&"e&member("cherche").text"e&&"recherchée
: "&return&return
![]()
![]()
![]()
![]()
repeat
with i = 1 to lstFichiersQuiCorrespondent.count
![]()
![]()
![]()
![]()
![]()
![]()
fichierQuiVaBien
= lstFichiersQuiCorrespondent.getPropAt(i)
![]()
![]()
![]()
![]()
![]()
![]()
lesoccurrences
= lstFichiersQuiCorrespondent.getProp(fichierQuiVaBien)
![]()
![]()
![]()
![]()
![]()
![]()
leMessage
= leMessage&fichierQuiVaBien&&"......(nombre d'occurrences trouvées
: "&&lesoccurrences&")"&return
![]()
![]()
![]()
![]()
end
repeat
![]()
![]()
end
if
![]()
![]()
member("resultat").text
= leMessage
end
if
end
Il nous reste maintenant à écrire le script mettant les noms de fichiers en rouge et en gras lorsque la souris passe dessus, et affichant le texte correspondant dans la fenêtre de texte lorsqu'on clique sur l'un de ces noms de fichiers. Ce script sera appliqué au sprite qui contient l'acteur champ "resultat".
La souris étant par définition mobile et fureteuse au dessus
de ce champ résultat, il va nous falloir surveiller en permanence sur
quel mot se trouve la souris, et mettre ce mot en rouge et en gras lorque ce
mot est un nom de fichier. Inversement, lorsque la souris quitte le mot, il
faut que le nom de fichier qui était en rouge et en gras redevienne noir
et en style normal.
Pour surveiller quel mot survole la souris en permanence, il nous faut un événement
répétitif.
Deux solutions s'offrent à nous : soit l'événement répétitif
du sprite on mouseWithin, lequel se produit tout le temps que la souris
se trouve sur le sprite, soit faire appel à notre moteur, qui continue
à tourner pour animer les ascenseurs lorsque ceux-ci sont sollicités.
Dans l'exercice, nous avons choisi d'adopter le mouseWithin, bien que celui-ci soit un peu lent.
Voyons comment mettre un mot survolé en surbrillance (à la manière
d'un lien hypertexte).
Nous aurons en fait la même instruction que celle qui nous a servi à
mettre en surbrillance les occurrences cherchées aux étapes 4 et
5 de l'exercice. Ces instructions, au leiu de porter sur un seul caractère,
porteront sur un mot entier. De la même façon que les caractères
sont indiqués dans un texte par leur rang, les mots ont aussi un rang,
un numéro, quil es indexe dans le texte.
Nous savons donc mettre un mot en surbrillance de la même façon
qu'un caractère à l'aide des instructions :
set the foreColor of word(n) of member("resultat") to
the foreColor of member("rougeRef")
set the fontStyle of word(n) of member("resultat") to "bold"
pour la mise en surbrillance,
set the foreColor of word(n) of member("resultat") to
the foreColor of member("noirRef")
set the fontStyle of word(n) of member("resultat") to "plain"
pour le retour à la normale, et où, dans les deux cas, n
est le numéro du mot dans le texte, le premier mot ayant le numéro
1, etc.
Il nous donc déterminer la valeur de n.
C'est très simple : il existe une propriété de l'animation
qui indique le rang du mot situé sous la souris, lorsque celle-ci survole
un sprite contenant un acteur champ. cette propriété s'appelle
the mouseWord. Elle renvoie le numéro du mot du texte,
et elle renvoie -1 si la souris n'est pas sur un champ.
NB : sur le même modèle, il existe aussi the
mouseChar et the mouseLine qui indiquent
respectivement le numéro du caractère et le numéro de ligne
survolés par la souris. Voir le dictionnaire lingo pour les détails.
Maintenant que nous connaissons le numéro du mot, il nous faut toutefois
vérifier que ce mot est bien un nom de fichier, et non pas n'importe
quel autre mot, dont des exemplaires existent également dans notre champ
résultat.
Pour savoir cela, nous devons nous servir du fait que les noms de fichiers portent
une extension, laquelle est .txt pour les fichiers ASCII (on remarque
du reste ici que cela sert de mettre les extensions aux noms d fichiers, même
quand l'OS de la machine sur laquelle on travaille ne les utilisent pas, MAC
au hasard !).
Nous allons donc tester si les quatre derniers caractères du mot survolés
par la souris sont ".txt". Si oui, on a affaire à un nom de
fichier, et on met ce nom en surbrillance.
Le traitement pour extraire ces quatre derniers caractères ne devrait
maintenant plus poser aucune difficulté :
- on initialise une chaîne à vide (appelée quatreDerniers
dans l'exercice),
- on récupère les quatre derniers caractères dans une boucle
de répétition décrémentale, dont le compteur va
du rang du dernier caractère du mot jusqu'à ce même rang-3,
- à la sortie de la boucle, la variable quatreDerniers contient
les quatre derniers caractères du mot survolé. Si quatreDerniers
est égal à ".txt", alors on est sur un nom
de fichier.
Pour la mise en surbrillance de ce mot et son retour à la normale si
la souris le quitte, il faut avoir recours à un petit artifice.
En effet, le mouseWithin est un événement répétitif.
Si nous contentons de mettre deux instructions :
quand la souris est sur le champ
mettre tout le texte en noir et en normal
mettre le mot sous la souris en rouge et en gras
fin
alors nous aurons une sorte de battement, puisque à chaque exécution
du mouseWithin, tout le texte sera remis en noir, y compris le mot
qui est sous la souris, avant de remettre ce seul mot en rouge et en gras.
Il nous faut donc détecter si le mot sous la souris a changé :
si non, on ne fait rien, si oui on met le nouveau mot en gras et en rouge, et
on met l'ancien mot en noir et en style normal.
Il nous faut donc garder, d'une exécutiuon du mouseWithin sur
l'autre, le souvenir du mot qui est sous la souris.
Pour garder ce souvenir, nous allons comme d'habitude nous doter d'une propriété
qui, à la fin de chaque mouseWithin, va contenir le numéro du
mot sous la souris. A l'exécution suivante du mouseWithin, on
testera si le mot qui est sous la souris cette fois-ci est le même qu'auparavant
ou non. J'ai appelé cette propriété ancienMot
dans l'exercice.
Par ailleurs, on remet tout le texte en noir et en style normal quand la souris
quitte le champ, c'est à dire sur un événement on mouseLeave.
Voici donc quel sera notre script appliqué au champ résultat
:
property spriteNum, ancienMot
On beginSprite me
ancienMot = 0
end
on mouseLeave
sprite(spriteNum).member.foreColor = member("noirRef").foreColor
sprite(spriteNum).member.fontStyle = "plain"
end
On mouseWithin me
lire le mot situé sous la souris
lire
la longueur de ce mot
initialiser
un variable quatreDerniers comme une chaîne vide
répéter
avec un compteur i depuis le la longueur du mot jusqu'à cette longueur
- 3
![]()
quatreDerniers
= quatreDernier auquel on ajoute le caractère numéro i du mot
fin
répéter
si quatreDernier
= ".txt alors
![]()
si
numéro du mot sous la souris est différent de ancienMot alors
![]()
![]()
mettre en rouge et en gras le mot sous la souris
![]()
![]()
mettre en noir et en normal l'ancienMot
![]()
fin si
sinon
![]()
mettre tout le texte en noir et en normal
fin si
ancienMot
= le numéro du mot sous la souris
end
et en code :
property
spriteNum, ancienMot
On
beginSprite me
ancienMot = 0
end
on
mouseLeave
sprite(spriteNum).member.foreColor = member("noirRef").foreColor
sprite(spriteNum).member.fontStyle = "plain"
end
on
mouseWithin
unMot = sprite(spriteNum).member.word[the
mouseWord]
longueurMot = unMot.length
quatreDerniers = ""
repeat with i = LongueurMot
down to (longueurMot - 3)
![]()
quatreDerniers
= unMot.char[i]&quatreDerniers
end repeat
if quatreDerniers = ".txt"
then
![]()
if
the mouseWord <> ancienMot then
![]()
![]()
set
the foreColor of word(the mouseWord) of member("resultat") to the
foreColor of member("rougeRef")
![]()
![]()
set
the fontStyle of word(the mouseWord) of member("resultat") to "bold"
![]()
![]()
set
the foreColor of word(ancienMot) of member("resultat") to the foreColor
of member("noirRef")
![]()
![]()
set
the fontStyle of word(ancienMot) of member("resultat") to "plain"
![]()
end
if
else
![]()
set
the foreColor of member("resultat") to the foreColor of member("noirRef")
![]()
set
the fontStyle of member("resultat") to "plain"
end if
ancienMot
= the mouseWord
end
Notre exercice
est presque fini. Il nous reste à afficher dans le champ leTexte le contenu
du fichier sur le nom duquel on a cliqué dans le champ résultat,
et mettre, dans ce texte, les occurrences de la sous-chaîne recherchée.
Il n'y a rien de difficile ici : ce sont des choses que nous avons déjà
faites.
lorsqu'on
clique sur le champ résultat
si
le clic a eu lieu sur un nom de fichier (c'est à dire si le mot sur lequel
on a cliqué est en rouge et en gras) alors
![]()
mettre
en noir et en normal le champ leTexte (au cas où il lui resterait d'autres
attributs d'un précédent affichage
![]()
ouvrir
le fichier dont le nom est sous la souris en lecture seule
![]()
lire
son contenu et le stocker dans une variable
![]()
fermer
le fichier
![]()
dans
le contenu, enlever les sauts de ligne (ASCII 10) pour ne garder que les retours
chariot
![]()
affichier
ce contenu dans le champ leTexte
fin
si
faire
appel à la fonction chercherTexte pour mettre les occurrences de la sous-chaîne
cherchée en rouge et en gras
fin
Deux remarques dans ce script :
- le fichier ASCII contient, à chaque saut de ligne la séquence
de caractères retour chariot + saut de ligne. Director affiche les sauts
de ligne sous la forme d'un petit carré (‚), ce qui est très
inesthétique (en fait ce sont des crochets vides mais ils apparaissent
comme un petit rectangle). Il faut donc éliminer ces saut de ligne de
code ASCII 10. Cela se fait dans une boucle de rpétion balayant le texte
du dernier caractère au premier, en détruisant le caractère
s'il a un code valant 10. On fait ce balayage du dernier au premier caractère,
donc à l'envers, pour ne pas perturber les index des caractères
qui n'ont pas encore été inspectés (problème déjà
vu à propos des listes àl'étape précédente).
- la fonction chercherTexte(uneChaine, unTexte) a déjà été
écrite pourle bouton de recherche. Or, si on peut accéder, depuis
un sprite, à une propriété d'un autre sprite, et que l'on
peut aussi faire exécuter une tâche, depuis un sprite, par une
méthode appartenant à un autre sprite, il semble qu'on ne puisse
pas faire appel à une telle méthode lorsque celle-ci demande des
arguments et renvoie une valeur. Il faut donc réécrire ici la
fonction chercherTexte() et j'ai modifié légèrment ce nom
en rechercherTexte() de manière à ne pas avoir deux méthodes
de même nom dans l'application.
Voici donc notre script, en code :
on mouseUp me
member("leTexte").foreColor
= member("noirRef").foreColor
member("leTexte").fontstyle
= "plain"
unMot = sprite(spriteNum).member.word[the
mouseWord]
if the foreColor of word(the
mouseWord) of member("resultat") = the foreColor of member("rougeRef")
then
![]()
leFichier.openFile(the moviePath&"lesTextes\"&unMot, 1)
![]()
leTexte = leFichier.readFile()
![]()
leFichier.closeFile()
![]()
repeat with i = leTexte.length down to 1
![]()
![]()
if charToNum(leTexte.char[i]) = 10 then
![]()
![]()
![]()
delete leTexte.char[i]
![]()
![]()
end if
![]()
end repeat
![]()
member("leTexte").text = leTexte
end if
rechercherTexte(member("cherche").text,
leTexte)
end
Je ne réécrit pas ici la méthode rechercherTexte : c'est la même que celle qui a été écrite précédemment. Reportez-vous au .dir téléchargeable.
Nous avons enfin
terminé notre exercice.
Il était
long mais
il a permis de voir de très nombreuse notions et techniques.
A l'issue de cet exercice, vous n'ignorez plus rien des listes, ni des techniques
se rattachant aux chaînes de caractères.
Toutefois, concernant ces dernières, nous n'aurons fait qu'un travail
mécanique. Un traitement informatique des chaînes de caractères
tenant copte du sens et de la fonction des mots demande rapidement des dispositions
beaucoup plus considérables de fait que les langues humaines comportent
des quantités de nuances, d'exceptions, de formes... Il faut alors s'appuyer
sur des dictionnaires d'une part, et faire tout un travail de cotation des mots
en fonction des contextes, il faut répertorier les expression régulières,
etc...
De tels traitements sortent du cadre de ce cours.
(*) : Nous retrouverons cette notion de pointeur dans la manipulation des bases de données. Lorsqu'on interroge une base de données et que celle-ci répond en retournant un extrait de ses tables, extrait appelé jeu d'enregistrement ou recordset, nous aurons le même type de pointeur pour nous déplacer d'enregistrement en enregistrement.
(**) : Où trouver le dictionnaire des
instructions d'un Xtra ? Dans la documentation, nous l'avons déjà
dit, même si celle-ci n'est pas toujours bien faite. Il existe une autre
manière d'obtenir un simple mémento, sorte de documentation abrégée
disponible depuis l'intérieur de Director même. Il suffit de taper,
dans la fenêtre de message put interface(xtra "nomDeLXtra").
Cette instruction, disponible et utilisée seulement en phase de développement,
affiche dans la même fenêtre de message un condensé des instructions
avec indication des paramètres nécessaires.
Une autre instruction en ligne à signaler, c'est celle qui permet de
voir la liste de tous les Xtras diponibles et installés. Et accessoirement
de vérifier l'orthographe exacte du nom d'un Xtra. Il s'agit de l'instruction,
toujours à taper dans la fenêtre de message, showxlib.
Toutes les instructions tapées directment dans la fenêtre de message
doivent être suivies d'un retour chariot pour être exécutées.
| Retour à la huitième étape |