簡介
Horspool是後綴搜索,大家都從左往右匹配,它反着來。也就是搜索已讀入文本中是否含有模式串的後綴;如果有,是多長,顯然,當後綴長度等於模式串的長度時,我們就找到了一個匹配。
Horspool算法思想:模式串從右向左進行匹配。對於每個文本搜索窗口,將窗口內的最後一個字符與模式串的最後一個字符進行比較。如果相等,則繼續從後向前驗證其他字符,直到完全相等或者某個字符不匹配。然後,無論匹配與否,都將根據在模式串的下一個出現位置將窗口向右移動。模式串與文本串口匹配時,模式串的整體挪動,是從左往右,但是,每次挪動後,從模式串的最後一個字符從右往左進行匹配。
實例 + 原理
下面我們來看一個實例:
加上匹配串和模式串如下:
首先從右向左進行匹配,c與c匹配成功,接着第二個字符b與a,匹配失敗(失配位置爲3)。
於是,從模式串當前位置往左尋找匹配失敗的那個字符,也即在模式串中尋找字符b上一次出現的位置(注意這裏的“上一次”是指在模式串中從當前失配位置往左找到的第一個與失配位置相同的字符);
結果我們在模式串中找到了字符b,其位置爲1,那麼就將模式串整體往右挪動,把剛纔找到的字符b與之前與匹配串中失配的字符b對齊。總共移動了多少位呢?移動了(3-1)位。
模式串整體挪動到b處對齊後,再從右向左開始匹配,此時發現其第一個需要匹配的字符d與c就匹配失敗(失配位置爲4),尼瑪,坑爹啊!那接下來怎麼辦?當然是跟上一步的方法一樣,在模式串中去找失配的那個字符d,如果在模式串中找到了d,將模式串平移,使其d字符與匹配串的d對齊。結果發現模式串中根本就沒有字符d。那接下來怎麼辦?直接將模式串平移到剛纔失配字符d後面的。這是因爲模式串中沒有字符d,那麼就不可能在匹配串中的d及其前面的字符中匹配成功。這一次我們移動的位數是4-(-1)=5位。
然後,又回到第1步的那種狀態,從模式串的最後一個字符開始匹配,即c與c匹配,a與a匹配啊,然後發現b與c不匹配,從而我們在模式串中找b字符上一次出現的位置,發現其位置爲1,移動模式串,將b字符與b字符對齊(如下圖),這次我們移動的位數是2-1=1位。
終於,在經歷第五步的那次挪動後,我們匹配成功了,是不是感覺匹配速度特別快?
有了以上實例,我們現在來抽取其一般規則,以方便編碼實現:
我們得到的規則只有一條,即:
字符串後移位數=失配字符位置-失配字符上一次出現的位置
如果失配字符根本就沒有出現在模式串中,我們將“失配字符上一次出現的位置”的值視爲-1。
代碼
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 28 23:11:27 2016
@author: zang
"""
def Horspool(text, pattern):
t = len(text)
p = len(pattern)
cur = 0 #起始指針cur 表示 在text上開始匹配的起始位置
results = [] # 存儲成功匹配的信息
flag = 0
mischar = ""
mispos = 0
while cur <= t - p:
for i in reversed(range(p)):
#print i,
if text[i+cur] != pattern[i]:
mischar = text[cur + i]
mispos = i
break
else:
flag += 1
#print flag
results.append(" "*cur + pattern + " "*(t - p - cur) + " " + str(cur+1) + " " + str(flag))
cur += 1
continue
for k in reversed(range(mispos - 1)):
if pattern[k] == mischar:
cur += (mispos - k)
break
if k == 0:
cur += mispos + 1
if flag == 0:
print "No find."
else:
print flag," matching results are listed below."
print "-------" + "-"*t + "-------"
print text
for line in results:
print line
print "-------" + "-"*t + "-------"
def main():
while 1:
text = raw_input("text: ")
pattern = raw_input("pattern: ")
if len(text) == 0 or len(pattern) == 0:
print "\nplease input text and pattern again!"
break
Horspool(text, pattern)
if __name__ == '__main__':
main()