TP - Algorithme simplifié de Horspool☘
Ce TP a pour but de vous faire programmer l'algorithme de recherche textuelle selon la méthode de Horspool, qui est une version simplifiée de l'algorithme de Boyer-Moore.
Rappel
Voici les deux principes de l'algorithme proposé par Nigel Horspool pour optimiser l'algorithme naïf :
-
Dans la fenêtre glissante, les caractères sont comparés de droite à gauche plutôt que de gauche à droite.
-
En cas de non-correspondance, le décalage de la fenêtre va dépendre du caractère de texte. Ce principe s’appelle la règle du mauvais caractère.
Téléchargez le fichier « à trous » TPE05.20.py
(clic droit -> [Enregistrer la cible du lien sous]) et enregistrez-le
dans le dossier [E05-Recherche_Textuelle]
.
Des exemples de tests sont proposés à partir des motifs et des textes
ci-après. Il faudra ajouter vos propres tests dans le main
de votre
programme.
Exemple de tests
motif1 = 'witch'
texte1 = 'A witch which switch'
motif2 = 'scribe'
texte2 = """Vous savez, moi je ne crois pas qu’il y ait de bonne ou de mauvaise
situation. Moi, si je devais résumer ma vie aujourd’hui avec vous, je dirais
que c’est d’abord des rencontres. Des gens qui m’ont tendu la main, peut-être à
un moment où je ne pouvais pas, où j’étais seul chez moi. Et c’est assez
curieux de se dire que les hasards, les rencontres forgent une destinée…
Parce que quand on a le goût de la chose, quand on a le goût de la chose bien
faite, le beau geste, parfois on ne trouve pas l’interlocuteur en face je
dirais, le miroir qui vous aide à avancer. Alors ça n’est pas mon cas, comme je
disais là, puisque moi au contraire, j’ai pu : et je dis merci à la vie, je lui
dis merci, je chante la vie, je danse la vie… je ne suis qu’amour ! Et
finalement, quand beaucoup de gens aujourd’hui me disent « Mais comment fais-tu
pour avoir cette humanité ? », et bien je leur réponds très simplement, je leur
dis que c’est ce goût de l’amour ce goût donc qui m’a poussé aujourd’hui à
entreprendre une construction mécanique, mais demain qui sait ? Peut-être
simplement à me mettre au service de la communauté, à faire le don, le don de
soi…"""
motif3 = 'ment'
texte3 = """Et d'abord, bourdonnement dans les oreilles, éblouissement dans
les yeux. Au-dessus de nos têtes une double voûte en ogive, lambrissée en
sculptures de bois, peinte d'azur, fleurdelysée en or; sous nos pieds, un pavé
alternatif de marbre blanc et noir. À quelques pas de nous, un énorme pilier,
véritable menhir, puis un autre, puis un autre; en tout sept piliers dans la
longueur de la salle, soutenant au milieu de sa largeur les retombées de la
double voûte. Autour des quatre premiers piliers, des boutiques de marchands,
tout étincelantes de verre et de clinquants; autour des trois derniers, des
bancs de bois de chêne, usés et polis par le haut-de-chausses des plaideurs et
la robe des procureurs. À l'entour de la salle, le long de la haute muraille,
entre les portes, entre les croisées, entre les piliers, l'interminable rangée
des statues de tous les rois de France depuis Pharamond; les rois fainéants,
les bras pendants et les yeux baissés; les rois vaillants et bataillards, la
tête et les mains hardiment levées au ciel."""
Enfin, pour vous aider à visulaiser la recherche, vous pouvez consulter ce
site :
https://people.ok.ubc.ca/ylucet/DS/BoyerMoore.html.
Partie A - Pré-traitement du motif et décalage☘
-
Dans l'optimisation de Horspool, le dictionnaire des « mauvais caractères » associe à chaque caractère du motif son indice « le plus à droite ».
Complétez la définition de la fonctionbad_carac_horspool()
qui prend en paramètre une chaîne de caractères (le motif) et qui renvoie un dictionnaire dont les clefs sont les différents caractères du motif associés à leur plus grand indice.1 2 3 4 5 6 7 8 9 10 11 12
def bad_carac_horspool(motif): """ motif - str, chaîne de caractères Sortie: dict - dictionnaire tel que : - les clefs sont les caractères de motif - les valeurs associées sont leur indice "le plus à droite" dans motif Le dernier caractère de motif n'est pas parcouru >>> motif = 'CAAGT' >>> bad_carac_horspool(motif) {'C': 0, 'A': 2, 'G': 3} """
Exemple de tests
>>> bad_carac_horspool(motif1) {'w': 0, 'i': 1, 't': 2, 'c': 3} >>> bad_carac_horspool(motif2) {'s': 0, 'c': 1, 'r': 2, 'i': 3, 'b': 4} >>> bad_carac_horspool(motif3) {'m': 0, 'e': 1, 'n': 2}
-
A partir du dictionnaire précédent, le décalage à réaliser en cas de non correspondance entre les caractères
motif[j]
ettexte[i+j]
est calculé de la manière suivante :- Ou bien
texte[i+j]
n’est pas dans le motif, alors on déplace la fenêtre à « droite » de ce caractère : la valeur du décalage estj+1
. -
Sinon, on note
k
le plus grand indice detexte[i+j]
dans le motif.- soit
k
<j
et on décale la fenêtre dej–k
pour « aligner »texte[i+j]
; - soit
k
\geqslantj
et on décale la fenêtre de1
comme pour l’algorithme naïf.
- soit
- Ou bien
Complétez la définition de la fonction decalage_horspool()
qui prend en
paramètres deux chaînes de caractères (le motif et le texte), deux entiers
strictement positifs (les indices i
et j
) et un dictionnaire des
mauvais caractères. Cette fonction renvoie le décalage entier à appliquer
à la fenêtre en cas de non correspondance entre texte[i+j]
et motif[j]
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Exemple de tests
>>> bad_carac = bad_carac_horspool(motif1)
>>> decalage_horspool(motif1, texte1, 0, 4, bad_carac)
2
>>> decalage_horspool(motif1, texte1, 2, 4, bad_carac)
5
>>> decalage_horspool(motif1, texte1, 7, 4, bad_carac)
1
>>> decalage_horspool(motif1, texte1, 5, 3, bad_carac)
3
Partie B - Détecter la présence du motif☘
Sans utiliser l'opérateur in
, et en programmant l'algorithme simplifié
de Horspool, complétez la définition de la fonction est_present_horspool()
qui prend en paramètres deux chaînes de caractères motif
et texte
.
Cette fonction renvoie True
si la chaîne motif
est présente dans la
chaîne texte
, elle renvoie False
sinon.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Exemple de tests
>>> est_present_horspool(motif1, texte1)
True
>>> est_present_horspool(motif2, texte2)
False
>>> est_present_horspool(motif3, texte3)
True
Une piste
J'espère que vous n'avez pas fait un simplie copier/coller du code de l'algorithme naïf. En effet, il ne faut pas oublier d'appliquer le premier principe développé par Horspool (cf. introduction de ce TP)...
Partie C - Positions et nombre d'occurrences☘
-
Copiez/collez et modifiez le code réalisé dans la partie précédente pour programmer le corps de la fonction
nb_occurrences_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
. Cette fonction renvoie le nombre d'occurrences de la chaînemotif
dans la chaînetexte
, elle renvoie0
simotif
n'est pas présent danstexte
.1 2 3 4 5 6 7 8 9 10 11 12
def nb_occurrences_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre d'occurrences de motif dans texte Recherche selon les principes de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_occurrences_horspool(motif, texte) 4 """
Exemple de tests
>>> nb_occurrences_horspool(motif1, texte1) 2 >>> nb_occurrences_horspool(motif2, texte2) 0 >>> nb_occurrences_horspool(motif3, texte3) 3
-
Copiez/collez et modifiez le code réalisé dans la fonction précédente pour programmer le corps de la fonction
positions_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
. Cette fonction renvoie le tableau (éventuellement vide) des positions de la chaînemotif
dans la chaînetexte
.1 2 3 4 5 6 7 8 9 10 11
def positions_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: list - Tableau des positions où trouver motif dans texte >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> positions_horspool(motif, texte) [2, 8, 20, 30] """
Exemple de tests
>>> positions_horspool(motif1, texte1) [2, 15] >>> positions_horspool(motif2, texte2) [] >>> positions_horspool(motif3, texte3) [21, 54, 1015]
Partie D - Nombre de comparaisons☘
-
Complétez la définition de la fonction
nb_comparaisons_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
.
Cette fonction renvoie le nombre de comparaisons effectuées pour déterminer (par exemple) les positions de la chaînemotif
dans la chaînetexte
en appliquant l'algorithme simplifié de Horspool de recherche textuelle.1 2 3 4 5 6 7 8 9 10 11 12 13
def nb_comparaisons_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: int - Nombre de comparaisons nécessaires pour déterminer les positions où trouver motif dans texte selon l'algorithme de recherche textuelle simplifié de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> nb_comparaisons_horspool(motif, texte) 32 """
Exemple de tests
>>> len(motif1) 5 >>> len(texte1) 20 >>> nb_comparaisons_horspool(motif1, texte1) 17 >>> len(motif2) 6 >>> len(texte2) 1145 >>> nb_comparaisons_horspool(motif2, texte2) 238 >>> len(motif3) 4 >>> len(texte3) 1035 >>> nb_comparaisons_horspool(motif3, texte3) 334
-
Comparez ces résultats avec ceux obtenus dans le TP précédent.
Cette optimisation semble-t-elle efficace ? Conjecturez un ordre de grandeur du coût en fonction den
etp
, oùn
est la longueur du texte etp
est la longueur du motif. -
Complétez la définition de la fonction
affichage_horspool()
qui prend en paramètres deux chaînes de caractèresmotif
ettexte
.
Cette fonction affiche dans la console la recherche des positions de la chaînemotif
dans la chaînetexte
en appliquant l'algorithme simplifié de Horspool de recherche textuelle.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
def affichage_horspool(motif, texte): """ motif - str, chaîne de caractères texte - str, chaîne de caractères Sortie: None - Affichage des alignements obtenus selon l'algorithme de recherche textuelle simplifié de Horspool >>> motif = 'CAAGT' >>> texte = 'ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT' >>> affichage_horspool(motif, texte) ATCAAGTTCAAGTCAGTCCCCAAGTTGATGCAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT CAAGT """
Exemple de tests
>>> affichage_horspool(motif1, texte1) A witch which switch witch witch witch witch witch witch witch