Vous devez m'envoyer (en dépôt sur le cahier de texte d'Ecole Directe ou si ce n'est pas possible par mail à thalesm@free.fr) un fichier nommé NOM_TP_recherche_textuelle.py avec NOM votre nom qui contiendra toutes les fonctions Python demandées dans le TP.
Le fichier de base avec les fonctions Python à développer est à télécharger : ici
Les fonctions Python présentes dans le fichier sont :
recherche_motif_naive(chaine,motif)pre_traitement(motif)
recherche_motif_horspool(chaine,motif)genere_chaine_ADN(lg)cree_jeu_tests_chaine_et_motif_ADN(exp1,exp2)compare_methodes_naive_et_horspool(jeu_tests)
Chaque fonction doit être documentée en utilisant les docstring et en incluant plusieurs jeux de tests utilisant la bibliothèque doctest.
La recherche d'une sous-chaine (appelée aussi motif) dans une chaîne de caractères est souvent utilisée en informatique.
Voici quelques exemples d'application :
En bio-informatique : recherche d'un motif composé de bases azotées (adénine (A), cytosine (C), guanine (G), thymine (T)) dans une séquence ADN.

Dans les moteurs de recherche.
Dans un traitement de texte, par exemple rechercher combien de fois apparaît le mot "Cosette" dans le roman "Les Misérables" de Victor Hugo.
On dispose d'une première chaîne de caractères chaine et d'une autre chaîne de caractères (de longueur inférieure à la première) motif.
Proposer le code d'une fonction Python recherche_motif_naive(chaine,motif) qui détecte la présence de motif dans la chaine de caractères chaine.
Cette fonction devra retourner une liste avec les positions du premier caractère de motif dans chaine.
Si motif n'est pas présent dans chaine la liste retournée sera vide.
Exemple :
chaine = "Paris ! Paris outragé ! Paris brisé ! Paris martyrisé ! Mais Paris libéré !"
motif = "Paris"
print(recherche_motif_naive(chaine,motif)
Doit afficher :
[0, 8, 24, 38, 61]
En effet, le motif "Paris" apparaît 5 fois dans la phrase proposée en positions 0, 8, 24, 38 et 61.
Cet algorithme a été proposé par Nigel Horspool et qui est une version simplifiée du meilleur algorithme connu : celui de Boyer-Moore.
Il repose sur les deux idées clefs suivantes :
Voici une animation qui permet de comprendre le principe de fonctionnement de l'algorithme de Horspool.
Pour établir les décalages à effectuer à chaque étape du traitement, on utilise un dictionnaire dont les clefs sont les lettres du motif et les valeurs le décalage par rapport à la fin du motif.
Proposer le code d'une fonction Python derniere_occurence(motif) qui construit le dictionnaire décrit ci-dessus.
Remarque : Il n'est pas utile de traiter la dernière lettre de motif.
Exemple :
derniere_occurence("rappel")
doit retourner le dictionnaire suivant :
{'r':5,'a':4,'p':2,'e:1}
En effet, en parcourant le mot rappel à partir de la fin (sans prendre en compte le dernier caractère), la lettre "e" apparait en position 1, la lettre "p" en position 2, la lettre "a" en position 4 et la lettre "r" en position 5.
Voici en en pseudo-code, une version possible de la fonction principale de l'algorithme de Horspool.
recherche_motif_horspool(,) = longueur() = longueur() // création du dictionnaire des décalages des lettres du motif = derniere_occurence() // On créé la liste des positions du premier caractère de motif dans chaine = Liste vide // On commence par la fin du motif = - 1 < = élement en position de = Faux = dernier élément de = éléments de compris entre les indices () et = Ajouter à = Vrai = Vrai = + 1 appartient à la liste des clefs de = + valeur de pour la clef = +
Coder en Python la fonction recherche_motif_horspool(chaine,motif).
On se propose de reproduire la recherche d'une séquence dans une chaîne ADN proposée dans l'animation présentée ci-dessus.
Proposer le code d'une fonction Python nommée genere_chaine_ADN(lg) qui génère aléatoirement une chaine ADN de longueur lg parmi les bases azotées "A","C","G" et "T".
Exemple : genere_chaine_ADN(10) peut retourner la chaîne ADN : "AACTGGTAGC".
Construction d'un "vérificateur" des fonctions recherche_motif_naive(chaine,motif) et recherche_motif_horspool(chaine,motif)
Voici le code Python de deux fonctions cree_jeu_tests_chaine_et_motif_ADN(exp1,exp2) et compare_methodes_naive_et_horspool(jeu_tests) qui construise un jeu de tests pour des chaînes ADN et des motifs différents et
vérifie que les résultats retournés par les deux fonctions de recherche du motif (méthode naïve et celle avec l'algorithme de Horspool) sont identiques.
def cree_jeu_tests_chaine_et_motif_ADN(exp1,exp2):
jeu_tests = []
for exposant in range(exp1,exp2):
lg_chaine = 2 ** exposant
chaine_ADN = genere_chaine_ADN(lg_chaine)
for lg_motif in range(1,lg_chaine//3):
pos_debut = randint(0,lg_chaine-lg_motif)
motif = chaine_ADN[pos_debut:pos_debut+lg_motif]
jeu_tests.append((chaine_ADN,motif))
return jeu_tests
def compare_methodes_naive_et_horspool(jeu_tests):
for test in jeu_tests:
chaine = test[0]
motif = test[1]
lst_positions_motif_methode_naive = recherche_motif_naive(chaine, motif)
lst_positions_motif_algo_Horspool = recherche_motif_horspool(chaine, motif)
assert lst_positions_motif_methode_naive == lst_positions_motif_algo_Horspool
Commenter le code de ces deux fonctions en ajoutant des docstrings dans les entêtes et décrire le jeu de tests généré.
Utiliser ces deux fonctions pour valider vos deux fonctions développées recherche_motif_naive(chaine,motif) et recherche_motif_horspool(chaine,motif).
Voici le fichier au format ".txt" du texte intégral du roman de Victor Hugo "Les Misérables" : Texte intégral "Les Misérables".
Proposer un code Python qui permet de répondre aux questions suivantes :
recherche_motif_naive(chaine,motif) et recherche_motif_horspool(chaine,motif) pour la recherche des mots proposés.Indications :
Pour lire le fichier du roman au format ".txt", on pourra utiliser le fragment de code suivant :
f = open(nom_fichier_texte, mode="r", encoding="utf8")
lignes = f.readlines()
qui permet d'ouvrir le fichier en mode lecture et de récupérer toutes les lignes du fichier dans la variable nommée lignes.
recherche_motif_naive(chaine,motif) et recherche_motif_horspool(chaine,motif) afin qu'elles retournent en plus de la liste des positions du motif dans la chaine recherchée,
le nombre d'étapes effectuées.Une idée d'implémentation : construire un dictionnaire des résultats dont les clefs seraient :
mot_recherche apparait dans le roman;mot_recherche avec l'algorithme naïf;mot_recherche avec l'algorithme de Horspool.
Pour la fonction de recherche naïve, donner le nombre de comparaisons effectuées caractère par caractère dans le pire des cas en fonction de la taille de la chaîne de départ lg_chaine et la taille du motif recherché
lg_motif.
Pour l'algorithme de recherche de Horspool, l'étude théorique de la complexité algorithmique dépasse le cadre de NSI.
Une étude "expérimentale" de la complexité algorithmique de l'algorithme de Horspool.
A l'aide des deux applications précédentes (motif dans une chaine ADN et recherche de mots dans un livre), utilisez les compteurs du nombre de comparaisons effectuées lettre à lettre pour estimer en moyenne le facteur nombre de recherches algorithme naïf / nombre de recherches algorithme de Horspool.
On peut montrer qu'en moyenne la complexité est de l'ordre de $O(3 \times lg\_chaine)$ et que dans le pire des cas la complexité est de l'ordre de $O(lg\_chaine \times lg\_motif)$.
L'algorithme de Boyer-Moore utilise un autre tableau dit du bon préfixe, qui permet d'optimiser un peu plus la recherche. Si vous êtes interessé en voici une implémentation en Python proposée ici.
L'algorithme de Boyer-Moore complet est implémenté dans le langage Python pour les fonctions find, index.
Auteur : Hugues Malherbe
Document inspiré des ressources suivantes :