] > String search

第 12 回 文字列検索

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

12-1. 決定性オートマトンとの等価性

本章では非決定性オートマトンが決定性オートマトンに変換できることを示し ます。 非決定性オートマトンでは一つの状態から複数の状態へ遷移します。 そして、次々と遷移した後、一つでも受理状態へ遷移する遷移の仕方があれば 入力を受理します。 そこで遷移可能な状態のリストを考えます。そのリストの各要素に対して、入 力を適応して、次に遷移可能な状態のリストを作ります。 非決定性オートマトンではあらかじめ状態数が決まってますので、遷移可能な 状態のリストも全状態の中から選ぶことで作れます。したがって、遷移可能な 状態のリストの数も有限個になります。 例えば、非決定性オートマトンの状態として 1, 2 ,3 の三つの状態があった とします。 その時、遷移可能な状態のリストは、{1}, {2}, {3}, {1,2}, {2,3}, {1,3}, {1,2,3} の七通りになります。 そして、これらのリスト同士の間で、入力が与えられた時、どのリストへ遷移 可能かを考えます。 このように、遷移可能な状態リスト間で、入力による相互の移り変わりを決め ることができます。これは、入力により一意に次のリストが決まるので、決定 性オートマトンになります。 開始状態一個だけのリストを新たな開始状態とし、もとの受理状態を含むすべ てのリストを新たな受理状態とします。

ではここで例を示します。 例えば、正規表現 .*aab を受理する非決定性オートマトンは次のようになり ます(簡単のため、入力アルファベットを a と b に限ってます)。

非決定性オートマトン

この非決定性オートマトンを決定性オートマトンに変換します。 但し、開始状態から到達可能な状態だけしか必要ないので、開始状態から処理 を始めて、必要な状態のみを書き出します。

状態リスト 入力 遷移先の状態リスト
1 a 1,2
b 1
1,2 a 1,2,3
b 1
1,2,3 a 1,2,3
b 1,4
1,4 a 1,2
b 1

また、もともとの受理状態 4 を含むリストを新たな受理状態とします。

決定性オートマトン

この決定性オートマトンを元に、入力文字列から.*aab と一致する回数を求め るプログラムを示します。 なお、ここでは有限個の状態を変数に収めるため、C 言語の列挙型という型宣 言を使いました。 これは num 列挙型名 { 名前リスト }; で定義します。また、 これは typedef の使用もできます。


#include <stdio.h>
typedef enum st { s1, s12, s123, s14 } STATUS;
main(){
  char c;
  int count=0;
  STATUS s=s1;
  while((c=getchar())!=EOF){
    switch(s){
    case s1:
      if(c=='a'){ s=s12; }
      else if(c=='b'){ s=s1; }
      break;
    case s12:
      if(c=='a'){ s=s123; }
      else if(c=='b'){ s=s1; }
      break;
    case s123:
      if(c=='a'){ s=s123; }
      else if(c=='b'){ s=s14; count++;}
      break;
    case s14:
      if(c=='a'){ s=s12; }
      else if(c=='b'){ s=s1; }
      break;
    }
  }
  printf("%d\n",count);
}

演習12-1

次の文字列が含まれる回数を数えるプログラムを作りなさい。

  1. abb
  2. abab
  3. abba

12-2. 正規表現の入力

前回の手法では、非決定性オートマトンから決定性オートマトンを構成してま した。そのため、遷移可能な状態なリスト間の関係を求めてました。 しかし、これを行うと、非決定性オートマトンの状態数を m とした時、 O2m 個のリスト間の関係を調べなければなりません。 これは、例えば正規表現を入力させるようなプログラムでは入力に対する効率 が非常に悪くなります。

ここでは、正規表現を文字列として与え、入力に何箇所マッチするかを効率良 く計算する方法を考えましょう。 文字列の長さを m とし、入力の長さを n とします。

駄目な方法は、正規表現に対応した非決定性オートマトンを作り、決定性オー トマトンに変換してから入力を一文字ずつ見ていく方法です。こうすると決定 性オートマトンへ変換する手間を考慮しなければならないので、必要な計算量 は O2m +n となります。

そこで、決定性オートマトンを完全に作らずに入力を読むことを考えます。 そのためには正規表現や、非決定性オートマトンだけを使って入力を判断する 必要があります。 そこで、非決定性オートマトンに対して、非決定的な状態遷移をそのまま計算 することを考えます。 ある瞬間に遷移可能な状態は複数存在しますが、それは高々正規表現の長さ m 程度です。 そして、その遷移可能な状態のそれぞれについて、入力文字を与えると、次に 遷移可能な状態を計算することができます。 次に遷移可能な状態も高々 m 個なので、そのための手間は結局 Om で計算できます。 入力一文字に対して Om の手間がかかるので、全体では Omn の手間がかかります。

なお、C 言語では正規表現を解釈し、文字列に対して適応する関数 regcomp, regexec が用意されています。

演習12-2

正規表現を解釈するには、カッコの解釈などが必要なため、それ自体文 法によって解析しなければなりません。 そこで、ここでは簡単のために、正規表現の一部である文字列を入力と仮定し、 その文字列を何回含むかを計算するプログラムを作りなさい。

演習12-3

指定した文字列を含む行を表示するプログラムを作りなさい。

参考

UNIX 系の OS では正規表現とマッチする行を表示するプログラム grep が用 意されています。

12-3. 参考: P=NP問題

オートマトンにして記憶装置としてテープを接続したものをチュー リング機械と言います。 決定性のチューリング機械で計算できるものと、現在のコンピュータで計算でき るものは本質的に等価であることが知られています。

入力の長さに対して計算量が多項式の問題について、決定性のチューリング機 械で計算できる問題のクラスを P と言い、非決定性のチューリン グ機械で計算できる問題のクラスを NPと言います。 これらが等しいかどうかは計算機科学上で重要な未解決問題で P=NP 問 題 と言います。

NP 問題に含まれるものに素因数分解、地図の三色彩色可能性問題(平面の地図 は四色で塗れる)、巡回セールスマン問題(都市間の交通費がわかっている時全 都市を予算内で回れるかどうかを決める問題)などがあります。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科