言語理論とコンパイラ

第四回 (2015 年 5 月 1 日)

正規表現

http://www.sw.it.aoyama.ac.jp/2015/Compiler/lecture4.html

Martin J. Dürst

AGU

© 2005-15 Martin J. Dürst 青山学院大学

今日の内容

前回の残り

今週の展望

これらは全て同じ力を持って、正規言語を定義・受理する

これらを表現する「正規表現」(regular expression) という協力な表現方法が存在

DFA の最小化

ある DFA から同等の最小の DFA は次のように作成可能:

  1. 状態を受理状態と非受理状態の二つの集合に分割
  2. それそれの状態からどの記号でどの集合に遷移するかを調査
  3. 現在の集合を、どの記号でも同じ集合に遷移する状態の部分集合に分割
  4. 2. と 3. を変更が無くなるまで繰り返す

最小化の目的:

DFA の最小化の一例

DFA の効率の良い実装

State   next_state[state_count][symbol_count]; /* 遷移表 */
Boolean final_state[state_count];     /* 受理状態かどうか */
State   current_state = start_state;  /* 初期状態で初期化 */
Symbol  next_char;                        /* 次の入力記号 */

while ((next_char=getchar()) != EOF &&       /* 入力終了 */
         current_state != no_state)        /* 行き止まり */
    current_state = next_state[current_state][next_char];
if (final_state[current_state])
    printf("Input accepted!");
else
    printf("Input not accepted!");

 

正規表現の応用例

計算機実習 I の演習問題 (04C1): ある文章中、&amp;, &quot;, &apos;, &lt;, &gt; を見つけ、それぞれを &, ", ', <, > に変換せよ。

Ruby で書くと次のようになる:

gsub /&quot;/, '"'
gsub /&apos;/, "'"
gsub /&lt;/, '<'
gsub /&gt;/, '>'
gsub /&amp;/, '&'

gsub は「文字列内全て置換」のメソッド

// の間は正規表現

正規表現の具体例

正規表現の原則

正規表現の意義

正規表現の形式な定義

アルファベットΣ 上の正規表現の言語
優先度 正規表現 条件 言語 備考

ε, a a ∈ Σ {ε} 又は {a}
低い r|s r, s が正規表現 L(r|s) = L(r) ∪ L(s) 集合和
低め rs r, s が正規表現 L(rs) = L(r)L(s) 連結
高め r* r が正規表現 L(r*) = (L(r))* 閉包
高い (r) r が正規表現 L((r)) = L(r)

L(r) は r によって定義される言語

優先度に要注意

正規表現自体の文法

正規表現の例

正規表現から NFA へ (文字、選択肢)

正規表現に対応する NFA は正規表現の部分表現から再帰的に作成可能

各部分表現に初期状態と受理状態が一つずつあり、これを大きいものにつなぎ合わせる

ε と a に対応する NFA は初期状態一つと受理状態一つとそれを結ぶ ε 又は a と書かれた矢印

r|s の NFA は r の NFA と s の NFA から次のように作成:

全体の初期状態から r と s の初期状態へと、r と s の受理状態から全体の受理状態へ ε で結ぶ

正規表現から NFA へ (連結、繰返し)

rs の NFA は r の受理状態と s の初期状態を ε で結んで、r の初期状態は rs の初期状態、s の受理状態は rsの受理状態。

r* の NFA は次のように作成:

全体の初期状態と r の初期状態、r の受理状態と全体の受理状態、全体の初期状態と全体の受理状態、そして r の受理状態と初期状態 (逆!) を ε で結ぶ。

正規表現の変換の例

正規表現: a|b*c

有限オートマトンから正規表現へ

変換は可能が、複雑

変換の原理:

  1. 状態 A から状態 B直接遷移できる正規表現を全ての状態の組み合わせのために作成
  2. 一個の状態だけを選んで、その状態の経由を含める正規表現を作成
  3. 2. のステップを繰り返して、経由できる状態を増加
  4. 途中で正規表現がどんどん複雑になるので、できる限り簡単化

正規表現の応用

実用化された正規表現: 記述上の違い

正規表現の便利な追加機能 (括弧内は相当する理論的な正規表現)

 

実用化された正規表現: 使い方の違い

実用化された正規表現の応用

実用化された正規表現の注意点

今週のまとめ

演習問題

(提出不要)

  1. 次の正規表現を NFA に変換し、NFA から DFA を作る: (a|c*)a|b
  2. 1. の言語を定義する右線形文法を作る。
  3. Σ = {0, 1} の 0 が偶数 (1 は何個でもよい) 語を受理する DFA を作る。
  4. (発展問題) 3. の言語の正規表現を作る。(ヒント: 変換するより正規表現を新たに作る方がいい)

宿題

提出期限と場所: 2015 年 5月 7日 (木) 19:00 まで O 棟 5 階の O-529 号室の前の箱に投入

形式: A4 一枚 (裏も使用可)

  1. 次の右線形文法に相当する NFA の遷移図を作りなさい
    S → εA | bB | cB | cC, A → bC | aD | a | cS, B → aD | aC | bB | a, C →εA | aD | a
    (注: 純粋な (右) 線形文法に ε は不可)
  2. 前回の宿題 2 の書換後の DFA (本資料参照) を右線形文法に変換しなさい
    (ヒント: 受理専用の状態 F を新設)
  3. 正規表現 ab|c*d を状態遷移図に変換しなさい
    (授業で説明した通り (ε遷移を全て含む) の結果と単純化した結果の最小限のもの両方を書きなさい)
  4. flex, bison, gcc, make,m4 の動作確認済みノート PC を持参