Boyer-Moore
Algo 26
Résumé du cours
L’algorithme de Boyer-Moore et la version simplifiée de Horspool permettent d’effectuer des recherches dans un texte efficace.
Version naïve de l’algorithme de recherche textuelle
def comparer(texte: str, motif: str, pos: int) -> bool:
j = 0
while (j < len(motif)) and (motif[j] == texte[pos + j]):
j += 1
# correspondance sur toute la fenêtre
return j == len(motif)
def decaler(pos: int) -> int:
return pos + 1
def recherche_naive(texte: str, motif: str) -> int:
"""
renvoie la position du motif dans le texte
-1 s'il n'est pas présent
"""
# dernière position = taille(texte) - taille(motif)
position = 0
while position <= len(texte) - len(motif):
if comparer(texte, motif, position):
return position
else:
position = decaler(position)
return -1
t = "atgatccatca"
assert recherche_naive(t, "cat") == 6
assert recherche_naive(t, "tca") == 8
assert recherche_naive(t, "dog") == -1
Recherche textuelle de Horspool
def pretraitement(motif: str) -> dict:
"""
renvoie le dictionnaire des décalages à appliquer
pour chaque lettre du motif (sauf dernière)
"""
decalages = dict()
# on s'arrête à l'avant dernière lettre du motif
for i in range(len(motif) - 1):
# len(motif)-1 est la position de la dernière lettre
decalages[motif[i]] = len(motif) - 1 - i
return decalages
def decaler(pos: int, decalages: dict, taille: int, lettre: str) -> int:
if lettre in decalages:
return pos + decalages[lettre]
else:
# si la lettre n'est pas dans le dico (= le motif)
return pos + taille
def decaler2(decalages: dict, taille: int, lettre: str) -> int:
try:
res = decalages[lettre]
except KeyError:
res = taille
return res
def comparer(texte: str, motif: str, pos: int) -> bool:
j = 0
while (j < len(motif)) and (motif[j] == texte[pos + j]):
j += 1
# correspondance sur toute la fenêtre
return j == len(motif)
def horspool(texte: str, motif: str) -> int:
"""
Returns:
int: la position du motif dans le texte, -1 sinon.
"""
decalages = pretraitement(motif)
position = 0
while position <= len(texte) - len(motif):
if comparer(texte, motif, position):
return position
else:
position = decaler(
position, decalages, len(motif), texte[position + len(motif) - 1]
)
# si on sort de la boucle, on n'a rien trouvé
return -1
assert pretraitement("cat") == {'c': 2, 'a': 1}
assert pretraitement("ring_ring") == {'r': 3, 'i': 2, 'n': 1, 'g': 5, '_': 4}
t = "atgatccatca"
assert horspool(t, "cat") == 6
assert horspool(t, "tca") == 8
assert horspool(t, "dog") == -1
t = "stupid_spring_ring"
m = "ring_ring"
assert horspool(t, m) == 9