基本思想
Sunday算法由Daniel M.Sunday在1990年提出,它的思想跟BM算法很相似。
只不過Sunday算法是從前往後匹配,在匹配失敗時關注的是主串中參加匹配的最末位字符的下一位字符。
- 如果該字符沒有在模式串中出現則直接跳過,即移動位數 = 模式串長度 + 1;
- 否則,其移動位數 = 模式串長度 - 該字符最右出現的位置(以0開始) = 模式串中該字符最右出現的位置到尾部的距離 + 1。
實例
下面舉個例子說明下Sunday算法。假定現在要在主串”substring searching”中查找模式串”search”。
剛開始時,把模式串與文主串左邊對齊:
結果發現在第2個字符處發現不匹配,不匹配時關注主串中參加匹配的最末位字符的下一位字符,即標粗的字符 i,因爲模式串search中並不存在i,所以模式串直接跳過一大片,向右移動位數 = 匹配串長度 + 1 = 6 + 1 = 7,從 i 之後的那個字符(即字符n)開始下一步的匹配,如下圖:
結果第一個字符就不匹配,再看主串中參加匹配的最末位字符的下一位字符,是‘r’,它出現在模式串中的倒數第3位,於是把模式串向右移動3位(m - 3 = 6 - 3 = r 到模式串末尾的距離 + 1 = 2 + 1 =3),使兩個‘r’對齊,如下:
匹配成功。
回顧整個過程,我們只移動了兩次模式串就找到了匹配位置,緣於Sunday算法每一步的移動量都比較大,效率很高。
偏移表
偏移表
在預處理中,計算大小爲∣∑∣的偏移表。
代碼實現
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 28 23:11:27 2016
@author: zang
"""
import re
def Sunday(text, pattern):
results = [] # 匹配結果
flag = 0
len_pattern = len(pattern)
len_text = len(text)
endIndex = len_text - len_pattern + 1
for i in range(0, endIndex):
for j in range(0, len_pattern):
if text[i + j] == pattern[j]:
if j == (len_pattern - 1):
flag += 1
results.append(" "*i + pattern + " "*(len_text - len_pattern - i) + " " + str(i+1) + " " + str(flag))
break
else:
t = i + len_pattern
if t >= len_text:
break
if text[t] in pattern:
array = [m.start() for m in re.finditer(text[t], pattern)]
move = len_pattern - array[len(array) - 1]
i = i + move - 1
else:
i = i + t - 1
break
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
Sunday(text, pattern)
if __name__ == '__main__':
main()