文字列マッチングアルゴリズム(KMP、BM、Sunday)、Python実装

4648 ワード

主に3種類の文字列マッチングアルゴリズム(KMP

BM

Sunday)
まとめます.この3つの文字列マッチングアルゴリズムの主な違いは、マッチング中に不整合ビットに遭遇した場合、どのようなポリシーでシフトするかということです.たとえば、次の2つの文字列があります.
 
文字列:ABCADAB ABCDABCDABD
検索文字列:ABCDA
 
3つのアルゴリズムの例を次に示します
KMP:このアルゴリズムでは、移動後の検索時に最初の不一致:A->Dに遭遇した場合、検索文字列から何ビット移動するかを決定します.KMPアルゴリズムの初期段階では、pi[0,...,4]={0,0,0,0,0,1}の検索文字列で生成されるテーブルが生成されます.この表は上記のシフトを決定します.このときのシフトは、3-pi[2](3文字が一致しているため)です.KMPアルゴリズムの鍵は,マッチング文字の初期生成テーブルであり,移動後から検索することである.
BM:このアルゴリズムでは、文字列検索は最初からではなく、最後から始まります.例えば、上記の例では、まずDとAを比較しています.違いがあるので、検索文字の中で後ろから前へマッチング検索を行い、右端のマッチング文字を見つけてからシフトします.見つからない場合、シフト長はマッチング文字と同じ長さです.以下のようになります.
文字列:ABCADAB ABCDABCDABD
検索文字列:ABCDA(2桁移動)
この場合は比較を継続するが、この場合の比較は上記の2つの過程を考慮し、もう1つは一致した文字列(DA)であり、検索文字列の接頭辞(A)が含まれており、このとき1~3ビット移動することは意味がないことが分かる.したがって、BMアルゴリズムの鍵は、2つのシフトのうちの最大シフトを見つけることであり、それを行うことである.
Sunday:上記の2つの文字列マッチングアルゴリズムは、検索文字の前処理に関連していますが、Sundayアルゴリズムはまったく異なると予想されています.同様に上記の例では,一致しない文字列が見つかった場合,Sundayアルゴリズムは全く異なる判定法を採用した.文字列のK+1文字目が先に見つかり、Kは検索文字の長さです.検索文字列にK+1文字目が含まれていない場合は、K+1ビットを直接移動します.そうでなければ、BMアルゴリズムに従って検索列の最右端の文字から末尾までの距離+1ビットを移動する.

    class StringPatternt(object):
        def __init__(self,chr,p):
            self.chr = chr;
            self.p = p;
            self.p_len = len(p);
            self.pi = [0 for i in range(self.p_len)];
        def set_pattern(self,p):
            self.p = p;
            self.p_len = len(p);
        def set_chr(self,chr):
            self.chr = chr;
            
        '''KMP'''
        def __kmp_partial_match_table__(self):
            k=0;q = 1;
            #self.pi[0] = 0;
            while q < self.p_len:
                while (k > 0) and (self.p[k] != self.p[q]):
                    k = self.pi[k-1];
                if self.p[k] == self.p[q]:
                    k = k+1;
                self.pi[q] = k;
                q = q+1;
            return 0;
        
        def string_pattern_kmp(self):
            self.__kmp_partial_match_table__();
            print(self.pi);
            list_size = len(self.chr);
            pi_len = len(self.pi);
            k=0;
            for q in range(list_size):
                while (k > 0) and (self.p[k] != self.chr[q]):
                    k = self.pi[k-1];
                if self.p[k] == self.chr[q]:
                    k = k+1;
                if k == pi_len:
                    return q-pi_len+1;
                #q = q+1;
            return 0;
        
        '''BM'''
        def __calc_match__(self,num):
            k=num;j=0;
            while k>=0:
                if self.p[-k] == self.p[j]:
                    k = k-1; j=j+1;
                    if k<=0:
                        self.pi[num-1] = num;
                        return 0;
                else:
                    if num == 1:
                        return 0;
                    self.pi[num-1] = self.pi[num-2];
                    return 0;
            
        def __init_good_table__(self):
            i=1;
            while i <= self.p_len:
                self.__calc_match__(i);
                i=i+1;
            print (self.pi);
            return 0;
        
        def __check_bad_table__(self,tmp_chr):
            i=1;
            while self.p_len-i >= 0:
                if self.p[-i] == tmp_chr:
                    return i;
                else:
                    i = i+1;
            return self.p_len+1;
        
        def __check_good_table__(self,num):
            if not num:
                return self.p_len;
            else:
                return self.pi[num];
        
        def string_pettern_bm(self):
            self.__init_good_table__();
            tmp_len = self.p_len;
            i = 1;
            while tmp_len <= len(self.chr):
                if self.p[-i]==self.chr[tmp_len-i]:
                    i = i+1;
                    if i > self.p_len:
                        return tmp_len-self.p_len;
                else:
                    tmp_bad = self.__check_bad_table__(self.chr[tmp_len-i])-i;
                    tmp_good= self.p_len-self.__check_good_table__(i-1);
                    tmp_len = tmp_len+ max(tmp_bad,tmp_good);
                    print(tmp_bad,tmp_good,tmp_len);
                    i=1;
            return 0;
        
        '''sunday'''
        def __check_bad_shift__(self,p):
            i=0;
            while i