![]() |
|||||||||||||||||||||||||||||||||||||||||||
(1)文字列探索とは 文字列探索(string searching)とは, ある文字列の中に,別の文字列が含まれているかどうか, 含まれている場合は,その位置を示すことです。 探索される側の文字列をテキスト(text), 探し出すための文字列をパターン(pattern)といいます。 (2)力まかせ法 パターンを1文字ずつずらしながら, テキスト中の文字列と照合していく単純な方法を 力まかせ法(brute forth method),単純法,素朴法等と呼びます。 ![]() ![]() [プログラム例] private int 力まかせ法(string 文字列, string パターン) { int P1=0; int P2=0; while(P1<文字列.Length && P2<パターン.Length) { if(文字列[P1] == パターン[P2]){ P1++; P2++;} else { P1 = P1 - P2 + 1; P2 = 0; } } if(P2==パターン.Length) return(P1 - P2); return -1; } private void button2_Click(object sender, System.EventArgs e) { string 文字列 = textBox1.Text; string パターン = textBox2.Text; label5.Text=力まかせ法(文字列, パターン).ToString(); }
(3)KMP法 力まかせ法では,不一致文字があると, パターンを移動して再びパターンの先頭から照合しています。 すなわち,それまでの照合結果が捨てられることになります。 そこで, D. E. KnuthとV. R. Pratt,J. H. Morris が,ほぼ同時期に考案した Knuth-Pratt-Morris 法,略してKMP法と呼ばれる方法では, パターンの文字列の特徴を活かして そこまでの照合結果を有効活用して探索します。 たとえば,以下のような探索を考えてみましょう。 ![]() (b)の段階では,6文字目が一致しませんが, パターンの1,2文字目と4,5文字目が同じですから, 3文字目から照合を始めれば良いことになります。 このようにパターンの特徴を活かすことで, 照合する開始位置を省略することができます。 ただし,照合のたびに照合開始位置を決めるのは効率が悪いので, 最初にテーブルを作成します。 (a) 1文字目で不一致の場合 ![]() (b) 2文字目で不一致の場合 ![]() (c) 3文字目で不一致の場合 ![]() (d) 4字目で不一致の場合 ![]() (e) 5字目で不一致の場合 ![]() (f) 6字目で不一致の場合 ![]() ■照合再開位置の設定 テーブルを作成するためには,パターン同士を1文字ずつずらしなら 以下のように,連続的に一致する文字数を カウンすることで作成することができます。 ![]() ![]() [プログラム例] private int KMP法(string 文字列, string パターン) { int P1=1; int P2=0; int[] skip=new int[256]; skip[P1]=0; while (P1<パターン.Length) { if(パターン[P1]==パターン[P2]) skip[++P1]=++P2; else if(P2==0) skip[++P1]=P2; else P2=skip[P2]; } P1=P2=0; while(P1<文字列.Length && P2<パターン.Length) { if(文字列[P1] == パターン[P2]){ P1++; P2++;} else if(P2 == 0) P1++; else P2=skip[P2]; } if(P2==パターン.Length) return(P1 - P2); return -1; } private void button3_Click(object sender, System.EventArgs e) { string 文字列 = textBox1.Text; string パターン = textBox2.Text; label5.Text=KMP法(文字列, パターン).ToString(); }
(4)BM法 この方法は, R. S. BoyerとJ. S. Moore により提案したアルゴリズムで, KMP法より簡単なアルゴリズムですが,効率のよい方法です。 Boyer-Moore 法,略してBM法と呼ばれます。 照合をパターンの末尾から行います。 一致しない文字を見つけた場合, 事前に用意した表により移動量を決めます。 例えば,以下のように4文字目で不一致のとき, 3文字ずらしても不一致になります。 ![]() これは,テキストの4文字目の”E”という文字が, パターンに入っていないからです。 すなわち,パターンに入っていない文字を見つけたら, 文字数分をずらすことができます。 以下のように一致した場合は,ひとつ前の文字で比較します。 ![]() このとき2文字ずらしても不一致ですので, 3文字分ずらしてよいことになります。 以下のように,パターンの文字数分が一致すれば,成功です。 ![]() 最初,以下のようなスキップ表を作成しておきます。 ここで,パターンの文字数をN, パターンの最後に出現する位置の添え字をKとします。 ![]() [プログラム例] private int BM法(string 文字列, string パターン) { int P1=0; int P2=0; int txtLen = 文字列.Length; int patLen = パターン.Length; int[] skip=new int[char.MaxValue+1]; for(P1 =0; P1 <= char.MaxValue; P1++) skip[P1]=patLen; for(P1 =0; P1 <= patLen - 1;P1++) skip[パターン[P1]]=patLen - P1 -1; // このとき,P1= patLen-1であることに注意 while(P1<文字列.Length) { P2=patLen - 1; while(文字列[P1] == パターン[P2]) { if (P2==0) return(P1); P1--; P2--; } P1 += skip[文字列[P1]]; } return -1; } private void button4_Click(object sender, System.EventArgs e) { string 文字列 = textBox1.Text; string パターン = textBox2.Text; label5.Text=BM法(文字列, パターン).ToString(); }
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() 上のタイトルをクリックします |
|||||||||||||||||||||||||||||||||||||||||||