読者です 読者をやめる 読者になる 読者になる

正規表現エンジンの実装(1)

これから数回をかけて正規表現エンジンをC言語で実装します。この回では、メタ記号('(',')', '|','?','+'..)無しの正規表現を作ります。すると結局、文字列の比較をするプログラムを作るということになります。例えば"./a.out hello hello"としたら"match\n"、"./a.out hello hell"とすると"no match\n"と標準出力されるようなものです。

1st commit


(正規表現)->(ポストフィックス ノーテーション)(PFN)->(NFA)に変換させてから、文字列にマッチするかどうか調べるという方式で実装します。正規表現からPNへの変換部分を実装するわけですが、"|"が導入できるようにするためには、どの文字と文字が接続されているかを指定する必要があります。例えば、"ab"はaとbが接続されていて、これを"ab."と表現することにします。"abc"はaとbが接続されていて、cは"ab."に接続されています。なので"ab.c."となります。ちょうど、逆ポーランド記法(rpn)と同じ要領です。

+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+char* reg2post(const char* re) {
+static char buf[8000];
+char* dst;
+int i = 0;
+  dst = &buf[0];
+  for(;*re;re++) {
+    if(i > 1) {
+      *dst++ = '.';
+    }
+    *dst++ = *re;
+    i++;
+  }
+  if(i > 1)
+    *dst++ = '.';
+  return buf;
+}
+
+void test(void);
+int main(void) {
+  test();
+  return 0;
+}
+void test(void) {
+  assert(!strcmp("a",reg2post("a")) && "a -> a");
+  assert(!strcmp("ab.",reg2post("ab")) && "ab -> ab.");
+  assert(!strcmp("ab.c.d.e.f.g.",reg2post("abcdefg")) && "abcdefg -> ab.c.d.e.f.g.");
+}
+

その後の展開


ここソースコード置いておきます。