|
Télécharger le .dir correspondant à cette étape (bouton droit -> enregistrer la cible) |
Maintenant que notre ascenseur est fonctionnel, et que nous savons que nous allons pouvoir le réutiliser comme bon nous semblera, nous allons implémenter le moteur de recherche dans le texte. Cette fonction de recherche sera semblable, à quelques détails près, à n'importe quelle commande "rechercher" figurant dans tous les menus "Edition" des applications commerciales courantes que nous avons l'habitude d'utiliser (traitement de texte, tableur, Director lui-même etc...). Voici quel
est son cahier des charges : |
Puisque c'est l'appui
sur le bouton qui va déclencher le processus de recherche, nous allons
nécessairement trouver un gestionnaire on mouseUp posé
sur le bouton.
Puisque nous avons spécifié qu'on ne pouvait lancer une recherche
si on n'avait rien saisi, nous allons également trouver, dans ce mouseUp,
une condition qui va vérifier que le champ de recherche n'est pas vide.
Nous pouvons donc
écrire :
quand on clique sur le bouton
si
le champ "cherche" n'est pas vide alors
![]()
faire
la recherche
fin
si
fin
Que va-t-on trouver
dans la proposition exprimée ci-dessus
par "faire la recherche" ?
Pour pouvoir faire cette recherche (et nous allons voir comment tout de suite
après), il faut que nous sachions :
- dans quel texte chercher,
- quoi chercher.
Toujours dans
le souci de pouvoir réutiliser notre fonction de recherche pour d'autres
cas, nous nous abstiendrons de développer tout le mécanisme du
moteur de recherche dans le mouseUp. En effet, si nous voulions réutiliser
notre traitement ailleurs, il nous faudrait alors réécrire (ou
recopier, ce qui revient au même) tout le code correspondant (et en cas
de modification, il faudrait alors reporter cette modification dans toutes les
occurrences de ce bloc de code qui figurerait dans notre application). - Je
l'ai déjà dit dans ce cours, mais on ne le répétera
jamais assez - .
Nous allons donc écrire une fonction (qui dans le cas présent,
puisqu'elle se trouve dans un script de sprite, est équivalente à
une méthode : la terminologie dépend essentiellement de l'endroit
où se trouve le bloc de code, et de l'objet auquel il s'applique).
Pour que la fonction sache quoi faire, il va falloir lui passer des "arguments",
lesquels ne sont rien d'autre que des paramètres dont la fonction va
avoir besoin pour effectuer la tâche qu'on va lui assigner. On peut remplacer
arguments, ou paramètres, par "des renseignements dont la fonction
va avoir besoin pour faire ce qu'on lui demande".
Dans l'exercice, j'ai appelé cette fonction "chercherTexte()".
Et comme nous lui passons deux arguments, nous écrirons, d'un point de
vue de la syntaxe : chercherTexte(uneChaîne, unTexte).
C'est volontairement que leTexte est devenu unTexte, et que
laChaîne est devenu uneChaîne. En effet, la manière
d'exprimer ces arguments indique à la fonction qu'elle doit attendre
deux chaînes de caractères. Au moment de l'appeler effectivement
pour lui faire faire sa tâche, nous remplacerons uneChaîne
et unTexte, par laChaîne et leTexte qui nous
intéressent. En attendant, la fonction, elle, sera écrite avec
les noms génériques uneChaîne et unTexte,
qui peuvent être considérés comme des variables locales
de la fonction. Elle seront remplacées, au moment de l'appel de la fonction,
par les valeurs que nous lui passerons effectivement.
Dans le cas présent,
comme nous l'avons relevé précédemment, la fonction a besoin
de savoir quoi chercher dans quel texte. Nous allons donc lui passer ces deux
renseignements en arguments. Pour pouvoir les lui passer, il va falloir les
stocker, dans le mouseUp, dans deux variables, qui seront locales ici,
puis leur survie sera assurée par leur passage à la fonction sous
forme d'argument.
Nous écrirons donc :
quand on clique sur le bouton
si
le champ "cherche" n'est pas vide alors
![]()
lire
le contenu du texte dans lequel rechercher et le stocker dans une variable appelée
leTexte
![]()
lire
le contenu de la chaîne à rechercher dans le champ "cherche"
et le stocker dans une variable appelée laChaîne
![]()
vider
le champ "résultat"
![]()
faire
appel à chercherTexte en utilisant laChaîne et leTexte comme arguments
fin
si
fin
Nous devons aussi
prévoir le cas où l'utilisateur désirerait faire plusieurs
recherches consécutives, et dans ce cas, à chaque appui sur le
bouton, nous devons vider le champ résultat pour faire place
nette à une autre indication de résultat. C'est pourquoi nous
avons ajouté la troisième ligne contenue dans le bloc si...
fin si.
NB : pour vider un acteur champ texte, il suffit de le remplir avec une
chaîne vide (qu'on exprime par deux guillemets doubles sans rien entre
les deux : ""), c'est à dire de lui fixer sa propriété
text à "". Attention : on ne peut pas régler
des caractéristiques de police (type, taille, style, couleur...) si le
champ contient une chaîne vide. Si l'on doit fixer ces attributs alors
que le champ doit apparaître vide à l'écran, il faut le
remplir avec un simple espace (invisible pour l'utilisateur, mais faisant que
le champ contient malgré tout quelque chose). On fixe alors la propriété
text à " " (au lieu de "").
Jusque là,
cela ne pose aucun problème de syntaxe et nous pourrons coder :
on mouseUp me
if
member("cherche").text <> "" then
![]()
laChaîne
= member("cherche").text
![]()
leTexte
= sprite(spriteSource).member.text
![]()
member("resultat").text
= ""
![]()
chercherTexte(laChaîne,
leTexte)
end
if
end
et puisque nous faisons appel à une fonction, nous devons l'écrire immédiatement, en la laissant vide pour l'instant. Mais, pour la cohérence de l'architecture de notre application, nous écrirons, pour l'instant, immédiatement après le mouseUp :
on chercherTexte (uneChaîne, unTexte)
end
Nous allons maintenant nous intéresser à ce que nous allons mettre dans notre fonction chercherTexte().
Le principe de la recherche sera le suivant : nous allons parcourir, par groupe de caractères, tout le texte dans lequel nous cherchons, groupes du même nombre de caractères que la sous-chaîne que nous cherchons. Si nous rencontrons un groupe de caractères qui est le même que celui que nous cherchons, alors nous relèverons son index (voir ci-dessous) de début dans une liste qui sera chargée de stocker les résultats.
Considérons la figure ci-dessous :

Elle
schématise le début d'un texte, lequel est une chaîne. Chaque
caractère est symbolisé par les tirets. En dessous de chaque tiret,
on a inscrit le numéro d'ordre du caractère dans la chaîne.
En effet, une chaîne de caractères peut-être assimilée
à une liste dont chaque caractère porte un numéro d'ordre,
qu'on appelle aussi un index (*).
A titre d'exemple, dans le schéma ci-dessus, on a supposé qu'on
cherchait une sous-chaîne de 5 caractères dans le texte source.
Nous allons donc lire le texte source par groupes de 5 caractères, en
glissant ; c'est à dire que nous allons regarder les caractères
1 à 5 du texte source, puis 2 à 6, puis 3 à 7, etc.
A chaque fois que nous aurons extrait un groupe de 5 caractères du texte
source, nous le comparerons avec la sous-chaîne recherchée. Si
les deux sont différents, on passe au groupe suivant, et ainsi de suite.
Si les deux sont identiques, alors il nous suffira de retenir, en le stockant
dans une liste (appelée dans l'exercice "lstTrouvailles"),
l'index du premier caractère du groupe.
Lorsqu'il s'agira de mettre ces groupes en évidence (en rouge et en gras
dans l'exercice) dans le corps du texte, l'index du premier caractère
du groupe suffit puisque nous en connaissons la longueur en terme de nombre
de caractères.
Puisque
nous allons lire notre texte source, par groupe de n caractères
en se décalant à chaque fois de une unité, nous pouvons
d'ores et déjà imaginer que nous allons avoir recours à
au moins une boucle de répétition.
Jusqu'où aller dans le texte ? Il est inutile de le lire jusqu'au dernier
caractère puisque lorsque le réliquat restant à examiner
sera plus court que la sous-chaîne à chercher, nous sommes sûrs
d'avoir une inégalité. Si nous cherchons une sous-chaîne
de n caractères, nous pourrons nous arrêter lorsque nous aurons
examiné les n derniers caractères du texte source. C'est à
dire la longueur du texte source moins la longueur de la sous-chaîne recherchée
diminuée de 1 caractère (si nous cherchons une sous-chaîne
de 5 caractères, nous aurons examiné les 5 derniers quand il en
restera 4 après lui).
D'autre
part, puisqu'à chaque fois qu'on se positionne sur un caractère
du texte source, il va falloir examiner ce caractère concaténé
avec les n-1 suivants (en effet, pour examiner n caractères,
une fois qu'on a relevé le premier du groupe, il faut en relever les
n-1 suivants de manière à avoir en tout n caractères),
on peut également imaginer que nous aurons, pour compter ces n-1
caractères, une autre boucle de répétition imbriquée
dans la première.
Pour ce faire, nous allons devoir disposer d'une variable locale. En effet,
nous lisons les caractères un par un. Pour pouvoir les comparer à
la sous-chaîne, il va falloir les concaténer, et il nous faut donc
un conteneur pour stocker le résultat de cette opération. Nous
avons appelé cette variable locale aComparer,
et nous la déclarons comme une chaîne vide AVANT d'entrer dans
la deuxième boucle de répétition. En effet, c'est une fois
qu'on s'est positionné sur un caractère du texte source, qu'on
va constituer la chaîne qui devra être comparée à
la sous-chaîne recherchée. Nous n'aurons pas à nous préoccuper
de réinitialiser cette variable : c'est une variable locale qui va donc
disparaître à la fin de la fonction, et qui sera recréée
à l'exécution suivante de la fonction.
NB
: En réalité, Lingo offre des fonctions qui simplifieraient ce
traitement. Il est possible effectivement de demander directement d'extraire
les x caractères situés entre deux index. La syntaxe
de cette instruction est member("leTexte").text.char[index1..index2]
où index1 est l'index du premier caractère de la sous-chaîne
à extraire et index2 l'index du dernier. Attention : ce n'est
pas une faute de frappe, la syntaxe exige bien deux points ( .. ) entre index1
et index2 ; ce ne sont pas des points de suspension.
J'ai choisi de ne pas les utiliser ici, car ce sont des instructions propres
à lingo, qui, en fait, font en arrière plan le traitement que
nous implémentons, nous, explicitement.
Nous allons donc pouvoir écrire, en pseudo-code :
on
chercherTexte(uneChaîne, unTexte)
lire
le nombre total de caractère du texte source et le nommer nbCharTotal
lire
le nombre de caractères de la sous-chaîne à chercher et
le nommer nbCaract
initialiser
une liste vide (pour l'instant, mais qui stockera les index) et la nommer lstTrouvailles
répéter
avec un compteur i de 1 jusqu'à nbCharTotal - (nbCaract - 1)
![]()
aComparer
= ""
![]()
répéter
avec un compteur j de 1 jusqu'à nbCaract
![]()
![]()
aComparer
= aComparer auquel on ajoute le caractère (i+(j-1)) de unTexte
![]()
fin
répéter
![]()
si
la chaîne aComparer = uneChaîne alors
![]()
![]()
ajouter
à lstTrouvaille l'index i
![]()
fin
si
fin
répéter
end
Deux remarques :
-
Pourquoi ce (i+(j-1))
?
i prend successivement les valeurs 1, puis 2, puis 3, etc.
j également.
Au début de la seconde boucle de répétition, le compteur
i, qu'on peut aussi considérer comme un pointeur dans le texte
source, est positionné sur un caractère donné du texte
source. Mais la sous-chaîne aComparer, elle, est vide.
Il nous faut donc lui ajouter les caractères i+0, i+1,
i+2... puisque le caractère numéro i fait partie
du groupe que l'on va comparer.
j démarrant à 1, c'est donc bien j-1 qu'il faut
ajouter à i pour obtenir les caractères qui nous intéressent.
Noter qu'on aurait pu initialiser le compteur j à 0. Il aurait
alors fallu le faire compter jusqu'a nbCaract - 1 et l'expression du
caractère aurait été i + j.
D'une manière générale, il est important de bien maîtriser
ces comptages, en fonction des origines qu'on se choisit, et la meilleure manière
de faire est de faire de petits schémas sur papier, en prenant des valeurs
numériques concrètes avant de généraliser.
A noter d'ailleurs également que dans un texte, en Lingo, le premier
caractère de la chaîne porte l'index 1 (et non pas 0 comme dans
d'autres langages).
-
Dans l'expression "aComparer
= aComparer auquel on ajoute le caractère (i+(j-1)) de unTexte",
on rencontre une syntaxe que nous avons déjà rencontrée
pour les valeurs numériques. Le signe = est ici l'opérateur
d'affectation et non pas l'opérateur de comparaison. Quand nous écrivions,
dans l'exercice des balles : sprite(n).locH = sprite(n).locH +1, nous
avions dit que nous lisions, à droite du signe =, la valeur
actuelle du locH, que nous lui ajoutions 1, puis que nous réinjections
cette nouvelle valeur dans le locH.
C'est ici exactement la même chose : nous lisons, à droite du signe
=, la valeur courante de la variable aComparer (qui est une
chaîne), nous lui ajoutons un caractère, et nous réinjectons
l'ensemble dans la variable aComparer, qui prend ainsi une nouvelle
valeur. En Lingo, l'opérateur de concaténation est "&"
(comme en Visual Basic ; en javascript ou ActionScript, c'est le signe "+",
l'ambiguïté étant levée par le contexte).
A la sortie de la boucle de répétition, aComparer contient
une chaîne de longueur nbCaract.
Nous
allons maintenant pouvoir coder :
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
![]()
![]()
lstTrouvailles.add(i)
![]()
end
if
end
repeat
end
Il ne nous reste plus qu'à mettre en surbrillance (ici en rouge et en gras), toutes les sous-chaînes qui ont été trouvées, et afficher le résultat dans le champ "resultat".
Comment
faire ?
Nous disposons maintenant d'une liste lstTrouvailles qui contient tous
les index des premiers caractères des occurrences de la sous-chaîne
trouvée. Il va donc nous falloir parcourir cette liste, et pour la parcourir,
nous allons à nouveau utiliser une boucle de répétition.
Comme nous connaissons la longueur de la sous-chaîne à mettre en
évidence, nous allons mettre les caractères qui la composent en
évidence un par un, et ceci avec une autre boucle de répétition
identique à celle qui nous permettait de constituer la variable aComparer
dans la section précédente de la fonction.
NB : On peut faire ici la même remarque que plus haut,
à savoir qu'il existe, en lingo, des commandes qui nous permettraient
de changer la couleur et le style de blocs entiers d'un nombre de caractère
donné au sein d'un acteur champ. Ces commandes connaissent les mêmes
bugs que décrits plus bas (syntaxe donnée par le dictionnaire
lingo ne fonctionnant pas).
Et
nous pourrons donc écrire :
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
![]()
![]()
lstTrouvailles.add(i)
![]()
end
if
end
repeat
répéter
avec un compteur i de 1 jusqu'au nombre de valeurs contenues dans lstTrouvailles
![]()
répéter
avec un compteur j de 1 jusqu'à nbCaract
![]()
![]()
mettre
le caractère d'index : valeur de l'élément de rang i dans
lstTrouvailles + (j-1)) en rouge
![]()
![]()
mettre
le caractère d'index : valeur de l'élément de rang i dans
lstTrouvailles + (j-1)) en gras
![]()
fin
répéter
fin
répéter
end
Les
deux instructions présentes à l'intérieur des boucles de
répétition peuvent paraître obscures à la première
lecture. Pour une fois, la forme codée, que nous allons voir tout de
suite, est plus claire.
Explicitons : la liste lstTrouvailles contient les index de tous les
débuts de sous-chaînes trouvées. En parcourant la liste,
le premier élément indique la valeur de l'index du premier caractère
de la première occurrence trouvée. Le deuxième élément
de la liste indique la valeur du premier caractère de la deuxième
occurrence trouvée, etc.
Donc, en prenant la valeur de l'élément de rang i à
l'intérieur de la boucle de répétition, on va lire successivement
tous les index de tous les premiers caractères de toutes les occurrences
trouvées.
On y ajoute j-1 pour la même raison qu'exposée plus haut
: ce premier caractère fait partie de l'occurrence, il faut donc prendre
index + 0, index + 1, index + 2, etc.
De la même façon que plus haut, on aurait pu initialiser le compteur
j à 0 et ajouter j seulement à chaque
index de premier caractère.
Il
nous reste à coder :
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
![]()
![]()
lstTrouvailles.add(i)
![]()
end
if
end
repeat
repeat
with i = 1 to lstTrouvailles.count()
![]()
repeat
with j = 1 to nbCaract
![]()
![]()
set
the forecolor of char (lstTrouvailles[i]+(j-1)) of member("leTexte")
to the forecolor of member("rougeRef")
![]()
![]()
set
the fontStyle of char (lstTrouvailles[i]+(j-1)) of member("leTexte")
to "bold"
![]()
end
repeat
end repeat
end
Deux remarques
à nouveau :
- à propos de la syntaxe : on trouvera dans le fichier
.dir téléchargeable, en commentaire dans le script "analyser",
la syntaxe donnée par le dictionnaire Lingo, sous forme de syntaxe pointée.
C'est un des rares bugs de Director, mais cette syntaxe indiquée par
le dictionnaire NE MARCHE PAS. Il faut le savoir, et utiliser l'ancienne syntaxe
dite "verbose" telle qu'elle est indiquée ci-dessus.
- à propos de la couleur : Director autorise deux codages
de couleur : par numéro de couleur dans la palette de 256 couleurs, ou
en valeurs rvb (rouge, vert, bleu). Si les valeurs rvb marchent très
bien pour les instructions de dessin (comme nous le verrons dans un prochain
exercice), c'est moins évident avec les propriétés color
et foreColor. La manière la plus simple de faire est de se créer
un ou plusieurs acteurs qui ne serviront pas directement à l'animation,
de leur affecter manuellement les couleurs qu'on souhaite utiliser et de dire
ensuite dans le programme "je veux la même couleur que celle
de cet acteur de référence". Voici pourquoi on trouvera
dans la distribution deux tels acteurs, l'un nommé noirRef et
l'autre rougeRef, et on trouvera dans la première ligne à
l'intérieur des instructions de boucle l'utilisation d'un tel acteur
de référence. Cette particularité est propre à lingo.
Il nous reste
deux choses à faire :
- afficher le résultat dans l'acteur "resultat"
- ne pas oublier de réinitialiser la couleur et le style du texte source
au démarrage de l'animation.
Pour
afficher le résultat, c'est très simple : il suffit de constituer
une chaîne de caractères donnant ce résultat, et d'affecter
cette chaîne à la propriété text du champ
resultat.
Cette chaîne se composera de morceaux qui seront constants, concaténés
avec les valeurs des deux variables suivantes : le nombre d'occurrences trouvées
(qui sera le count de la liste lstTrouvailles, et le rappel de la sous-chaîne
que nous cherchions. Nous utilisons pour cela l'opérateur de concaténation
vu plus haut : "&".
D'autre part, comme nous sommes soucieux de fabriquer un produit impeccable,
nous allons mettre une condition qui vérifiera si on a trouvé
0 ou 1 occurrence, ou si on en a trouvé plusieurs. Nous fabriquerons,
selon le cas, une chaîne où les parties constantes seront au singulier
ou au pluriel.
Dernière particularité de l'instruction qui fabrique cette chaîne
de message (appelée leMessage dans l'exercice)
: pour le rappel de la sous-chaîne recherchée, et donc citer cette
sous-chaîne dans leMessage, il va nous falloir afficher des guillemets.
Or les guillemets, sont eux-mêmes, dans le langage, des caractères
réservés, délimiteurs de chaînes de caractères.
Nous allons donc utiliser un autre mot clé du langage qui signifie que
c'est bien le caractère guillemets qu'on veut afficher dans leMessage,
et ce mot clé est QUOTE. Il en existe quelques
autres tels que TAB ou RETURN.
Nous les verrons en leur temps.
Nous pourrons
donc terminer notre script d'analyse de la manière suivante :
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
![]()
![]()
lstTrouvailles.add(i)
![]()
end
if
end
repeat
repeat
with i = 1 to lstTrouvailles.count()
![]()
repeat
with j = 1 to nbCaract
![]()
![]()
set
the forecolor of char (lstTrouvailles[i]+(j-1)) of member("leTexte")
to the forecolor of member("rougeRef")
![]()
![]()
set
the fontStyle of char (lstTrouvailles[i]+(j-1)) of member("leTexte")
to "bold"
![]()
end
repeat
end repeat
if
lstTrouvailles.count < 2 then
![]()
leMessage
= "Le moteur de recherche a trouvé "&lstTrouvailles.count()&"
occurrence de la sous-chaîne"&"E&laChaîne"E&&"recherchée
dans le texte"
else
![]()
leMessage
= "Le moteur de recherche a trouvé "&lstTrouvailles.count()&"
occurrences de la sous-chaîne"&"E&laChaîne"E&&"recherchée
dans le texte"
end
if
member("resultat").text
= leMessage
end
On remarquera qu'après le mot "trouvé" et avant le mot "occurrence", on a mis des espaces pour respecter l'espacement des mots dans le résultat final de la concaténation. En revanche, avant et après les deux exemplaires du mot-cé QUOTE, on n'a pas mis d'espace, mais un double "&" : &&.
C'est une particularité de Lingo : en utilisant && comme opérateur de concaténation, on introduit automatiquement un espace entre les deux morceaux de chaîne concaténés.
Il nous reste
à réinitialiser les couleurs et le style de la police :
- au démarrage de l'application,
- quand on fait des recherches successives, donc à chaque appui sur le
bouton.
Pour
cela, nous ne ferons pas le détail de quel caractère est dans
telle couleur ou tel style, mais nous remettrons les couleurs et styles originaux
sur l'ensemble de l'acteur contenant le texte source.
Nous rajouterons donc les deux lignes suivantes dans le prepareMovie
et dans le mouseUp du bouton :
member("leTexte").foreColor
= member("noirRef").foreColor
member("leTexte").fontStyle
= "plain"
et là, lorsqu'il s'agit de l'acteur champ entier, la syntaxe à point fonctionne.
Notre moteur de recherche, dans sa version première, est terminé.
Il
reste à faire une remarque en guise de conclusion :
J'ai dit
plus haut que nous avions écrit là une fonction réutilisable.
Ce n'est pas tout à fait vrai : en effet, si la fonction marche quels
que soient le texte source et la sous-chaîne à chercher qu'on lui
passe en argument, elle va toujours changer la couleur et la graisse des caractères
trouvés (désignés par leur index), dans le texte qui est
contenu dans l'acteur leTexte, et ce, même si on applique la
recherche à un autre texte. Ce qui est un non-sens.
Par ailleurs, le résultat sera toujours affiché dans le champ
"resultat". Or si, pour une raison ou pour une autre, nous
souhaitions afficher ce résultat ailleurs, il faudrait réécrire
la fonction.
Une vraie fonction réutilisable utiliserait deux arguments supplémentaires
: l'acteur champ dans lequel modifier les caractères (alors que nous
nous sommes contentés, nous, de récupérer son contenu dans
une variable et par ailleurs de le citer nommément (donc "en dur"),
et l'acteur champ dans lequel afficher le résultat (alors que nous l'avons
également cité nommément).
La fonction
serait alors modifiée ainsi :
on
chercherTexte(uneChaîne, unActeurSource, unActeurCible)
nbCaract
= uneChaîne.length
nbCharTotal
= member(unActeurSource).text.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
![]()
![]()
lstTrouvailles.add(i)
![]()
end
if
end
repeat
repeat
with i = 1 to lstTrouvailles.count()
![]()
repeat
with j = 1 to nbCaract
![]()
![]()
set
the forecolor of char (lstTrouvailles[i]+(j-1)) of member(unActeurSource)
to the forecolor of member("rougeRef")
![]()
![]()
set
the fontStyle of char (lstTrouvailles[i]+(j-1)) of member(unActeurSource)
to "bold"
![]()
end
repeat
end repeat
if
lstTrouvailles.count < 2 then
![]()
leMessage
= "Le moteur de recherche a trouvé "&lstTrouvailles.count()&"
occurrence de la sous-chaîne"&"E&laChaîne"E&&"recherchée
dans le texte"
else
![]()
leMessage
= "Le moteur de recherche a trouvé "&lstTrouvailles.count()&"
occurrences de la sous-chaîne"&"E&laChaîne"E&&"recherchée
dans le texte"
end
if
member(unActeurCible).text
= leMessage
end
Dans
laquelle unActeurSource et unActeurCible seraient passés
comme chaînes de caractères exprimant le nom de chacun de ces acteurs.
Ainsi rédigée, notre fonction peut alors être mise en script
d'animation, à la suite du prepareMovie, et elle est réellement
réutilisable.
(*)
NB : En réalité, dans un langage de programmation, les chaînes
de caractères n'existent pas. Il n'existe que des données de type
caractère, représentant chacune un caractère unique. C'est
le cas dans les langages de bas niveau comme par exemple le C. Lorsqu'on a besoin
de manipuler une chaîne, on manipule en fait un tableau (une liste), dans
lequel figurent, à la suite les uns des autres, tous les caractères,
considérés chacun comme donnée unique, composant la chaîne.
Ce qui explique que chaque caractère porte un index, exactement comme
un élément d'une liste porte un rang, comme nous l'avons appelé
lorsque nous l'avons utilisé (exercice de l'avion par exemple).
Cette manière de manipuler les caractères lorsqu'on a besoin d'une
chaîne est peu commode. C'est pourquoi les langages dits "évolués"
(comme Lingo, ActionScript ou Visual Basic, mais il y en a beaucoup d'autres)
ont des fonctions internes, totalement transparentes et invisibles pour celui
qui programme, qui prennent en charge ces tableaux de bas niveau composés
de caractères uniques, pour les concaténer tous, et présenter
une entité que nous pourrons alors manipuler globalement comme ce que
nous appelons une chaîne, aussi longue soit-elle.
Il n'est donc pas étonnant que nous retrouvions, à propos des
chaînes, des fonctions qui sont assez semblables à celles des listes.
| Retour à la troisième étape |