先読みと後読みの可能な、O(N)の正規表現エンジンの実装

 先読みと後読みの可能な、O(N)の正規表現エンジンの実装

https://cybozu.connpass.com/event/53121/ での発表資料です。

Db1b7e3c6fe6f6a0e9752b2c19bf5473?s=128

TSUYUSATO Kitsune

March 30, 2017
Tweet

Transcript

  1. 先読みと後読みの可能な、 O(N)の正規表現エンジンの実装 @ m a k e _ n o

    w _ j u s t @ M a k e N o w J u s t
  2. 流れ 1. やりたいこと 2. どうやって? i. 先読み・ 後読みを予め処理する方法 ii. Boolean

    Finite Automata(BFA) を使う方法 3. 現在までの進捗 4. 今後の展開 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 2
  3. やりたいこと 先読みと後読みの可能な、O(N)の正規表現エンジンの実装 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 3

  4. やりたいこと 先読みと後読みの可能な、O(N)の正規表現エンジンの実装 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 4

  5. やりたいこと 先読みと後読みの可能な、O(N)の正規表現エンジンの実装 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 5

  6. やりたいこと 「 正規表現の先読み・ 後読み」 A ・ B ・ C を含む文字列にマッチする正規表現は、

    . * ( A . * B . * C | A . * C . * B | B . * A . * C | B . * C . * A | C . * A . * B | C . * B . * A ) . * のように書ける。(53 文字) 同じものを先読みを使って書くと、 ( ? = . * A ) ( ? = . * B ) ( ? = . * C ) . * のようになる。(23 文字) 複雑なものをより短かく書くことができる。 表現力が高い。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 6
  7. やりたいこと 「O(N)」=線形時間 入力の文字列の長さNに比例する時間で正規表現のマッチングを行う。 ( そのための準備にかかる計算量は考慮しない) ( 理論上は) 効率的。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装

    7
  8. どうやって? 正規表現で表現できるパター ンと決定性有限オー トマトン(DFA) で 受理できる文字列は等しい。 決定性有限オー トマトンは文字列の長さNに比例する時間で 受理するかどうかを判定できる。 →

    正規表現から決定性有限オー トマトンに変換できればよい。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 8
  9. どうやって? 正規表現から非決定性有限オー トマトン(NFA) に変換する方法は よく知られている。 Thompsonn 構成 Glushkov 構成 …

    しかし、 これらは正規表現の先読み・ 後読みを考慮しない。 ※ 非決定性有限オー トマトンから決定性有限オー トマトンへはRabin‑Scott の Powerset 構成が利用できる。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 9
  10. どうやって そこで、 先読み・ 後読みを含む正規表現を処理できる方法を 2 種類考えた。 1. 先読み・ 後読みを予め処理する方法 2.

    Boolean Finite Automata(BFA) を使う方法 これらを説明する。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 10
  11. 先読み・ 後読みを予め処理する方法 具体例を挙げて説明します。 このような正規表現: ( ? = . * f

    o o ) . * ( ? < = b a r . * ) に対して、 このような文字列: o o f o o a a b a r o o のマッチングを行ってみます。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 11
  12. 先読み・ 後読みを予め処理する方法 先読み・ 後読みを取り出す。 ( ? = . * f

    o o ) . * ( ? < = b a r . * ) → 1 . * 2 1: ( ? = . * f o o ) 2: ( ? < = b a r . * ) 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 12
  13. 先読み・ 後読みを予め処理する方法 先読み・ 後読みの正規表現を入力文字列の各位置からマッチングし、 その結果を記録する。 1: ( ? = .

    * f o o ) 2: ( ? < = b a r . * ) また、1 文字目より前の先読み、 最後の文字より後ろの後読みに 対応するため、 入力文字の前後に ^ と $ を追加する。 ^ o o f o o a a b a r o o $ 1 1 1 1 . . . . . . . . . . . . . . . . . . . . 2 2 2 2 ※ この処理は先読み・ 後読みがいくつあっても入力文字列の長さに 対して線形時間で行える。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 13
  14. 先読み・ 後読みを予め処理する方法 ^ o o f o o a a

    b a r o o $ 1 1 1 1 . . . . . . . . . . . . . . . . . . . . 2 2 2 2 文字とその位置でマッチした先読み・ 後読みの組を列にする。 ( ' ^ ' , { 1 } ) , ( ' o ' , { 1 } ) , ( ' o ' , { 1 } ) , ( ' f ' , { 1 } ) , ( ' o ' , { } ) , … … 中略… … , ( ' a ' , { } ) , ( ' r ' , { 2 } ) , ( ' o ' , { 2 } ) , ( ' o ' , { 2 } ) , ( ' $ ' , { 2 } ) これを入力列として受理・ 非受理の判定のできる 決定性有限オー トマトンを 1 . * 2 から作る。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 14
  15. 先読み・ 後読みを予め処理する方法 2 段階に分けて行う。 1. まず非決定性有限オー トマトンに変換して(Thompson 構成)、 2. それを決定性有限オー

    トマトンに変換する(Powerset 構成)。 Powerset 構成の際に少し工夫して、 1 や 2 を一文字も消費しない 特殊な文字として扱う。 そしてε 閉包に 1 や 2 も含めるようにし、 文字と組にして 遷移の条件とする。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 15
  16. 先読み・ 後読みを予め処理する方法 こうして出来たDFA は、 次のようなものになる。 s1 s2 (・, {1}) s3

    (・, {1, 2}) (・, {}), (・, {1}) (・, {2}), (・, {1, 2}) (・, {}), (・, {1}) (・, {2}), (・, {1, 2}) 初期状態は s 1 、 終了状態は s 3 。 ・ は任意の一文字( ^ と $ も含む) を意味する。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 16
  17. 先読み・ 後読みを予め処理する方法( 問題点) これでO(N)で先読み・ 後読みを含む正規表現のマッチングができる。 ( 全体としてO(N)の処理しか含まないので) しかし、 いくつか問題点が存在する。 1.

    先読み・ 後読みがネストすることができない。 2. O(N)とはいえ3 回もDFA によるマッチングをすることになる。 というわけで、 もう一つの方法を考えている。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 17
  18. Boolean Finite Automata(BFA) を使う方法 Boolean Finite Automata(BFA) もしくは、 Alternating Finite

    Automata(AFA) といわれるものがある。 これは有限オー トマトンを、 単一の状態の代わりに 論理式か論理値で状態を持つように拡張したもので、 有限オー トマトンの否定、 交差(intersection) を単純に表現できる。 オー トマトンの交差によって、 先読み・ 後読みを 簡潔に表現できることが期待できる。 しかも決定性有限オー トマトンに変換できる。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 18
  19. Boolean Finite Automata(BFA) を使う方法( 問題点) バリエー ションがある。 状態を論理式で持つか、 論理値で持つか 文字列を先頭から読み込んでいくか、

    末尾から読み込んでいくか 2×2 で4 通り。 このどれを選んでも、 先読みか後読みのどちらかしか 簡単に表現できない。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 19
  20. Boolean Finite Automata(BFA) を使う方法( 問題点) 論理値 論理式 先頭から 後読み 先読み

    末尾から 先読み 後読み 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 20
  21. Boolean Finite Automata(BFA) を使う方法( 問題点) 先頭から、 論理値と論理式を同時に更新していって最後にそれを 適用するようにすれば先読みと後読みを同時に同じ枠組みで 処理できるかもしれない。 →

    しかし、 その場合どうやって決定性有限オー トマトンに変換すれば 良いか( 現状) 分からない。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 21
  22. 現在までの進捗 2017 年の1 月に開始。 「 先読み・ 後読みを予め処理する方法」 については実装して、 線形時間で処理できることなどを確認した。 「Boolean

    Finite Automata(BFA) を使う方法」 については現在、 実装・ 考察を重ねている。 https://github.com/MakeNowJust/re‑research https://github.com/MakeNowJust/bfa 先読みと後読みの可能な、O(N) の正規表現エンジンの実装 22
  23. 今後の展開 今後も継続予定。 BFA の考察を進めて、 先読み・ 後読みを簡潔に実装できないか考える。 BFA 以外にも使えそうな方法がないかを考える。 先読みと後読みの可能な、O(N) の正規表現エンジンの実装

    23