字符串匹配算法 之 Sunday

基本思想

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()

這裏寫圖片描述

發佈了126 篇原創文章 · 獲贊 94 · 訪問量 46萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章