正規表現からNFAを作成するときに、「各ステップを説明する」問題があります。質問は次のとおりです。
次の正規表現を非決定的な有限状態オートマトン(NFA)に変換し、使用するアルゴリズムのステップを明確に記述します:(b | a)* b(a | b)
単純な3ステートマシンを作成しましたが、それは直観に基づいています。これは私の講師が書いた過去の試験からの質問であり、彼はまたトンプソンのアルゴリズムの次の説明を書いた: http://www.cs.may.ie/staff/jpower/Courses/Previous/parsing/node5 .html
「各ステップを明確に説明する」方法を誰もが明確にできますか?これは、従うべきステップを備えたアルゴリズムというよりも、基本的なルールのセットのように思えます。
多分私はどこかで詳しく説明したアルゴリズムがありますが、これまでのところ、経験に基づいた推測でそれらを作成しました。
一般的なアプローチの短いバージョン。
Thompson-McNaughton-Yamada Construction Algorithm、または単に「Thompson Construction」と呼ばれるアルゴリズムがあります。中間のNFAを作成し、演算子の優先順位を尊重しながら、途中でピースを埋めます:最初の括弧、次にKleene Star(例えばa *)、次に連結(例えばab)、それに続く交替(例えばa | b).
ここに、(b | a)* b(a | b)のNFAを構築するための詳細なウォークスルーがあります。
最上位の構築
括弧を処理します。注:実際の実装では、コンテンツの再帰呼び出しを介して括弧を処理することは理にかなっています。わかりやすくするために、かっこ内の評価は延期します。
Kleene Stars:1つだけ*があるため、PというプレースホルダーKleene Starマシンを作成します(後でb | aが含まれます)。中間結果:
連結:Pをbに接続し、bをQ((a | b)を含むプレースホルダーマシンに接続します。中間結果:
括弧以外の変更はないため、スキップします。
今、私たちはP * bQマシンに座っています。 (プレースホルダーPおよびQは単なる連結マシンであることに注意してください。)b | aのP EdgeをNFAで置き換え、上記の手順を再帰的に適用してa | bのQ EdgeをNFAで置き換えます。
Building P
スキップ。括弧なし。
スキップ。クリーネ星なし。
スキップ。コンタテネーションなし。
B | aの代替マシンを構築します。中間結果:
Pの統合
次に、P * bQマシンに戻り、P Edgeを削除します。 PエッジのソースはPマシンの開始状態として機能し、PエッジのデスティネーションはPマシンの宛先状態として機能します。また、その状態を拒否します(受け入れ状態であるという特性を取り除きます)。結果は次のようになります。
ビルディングQ
スキップ。括弧なし。
スキップ。クリーネ星なし。
スキップ。コンタテネーションなし。
A | bの代替マシンを構築します。ちなみに、交代は可換であるため、a | bは論理的にb | aと同等です。 (読む:怠thisからこのマイナーな脚注図をスキップします。)
Qの統合
Q Edgeを、作成した中間マシンb | aマシンで置き換えることを除いて、上記のPで行ったことを行います。これが結果です:
多田!えー、つまり、QED。
もっと知りたいですか?
上記のすべての画像は、 正規表現を非決定性有限オートマトンに自動的に変換するオンラインツール を使用して生成されました。 Thompson-McNaughton-Yamada Constructionアルゴリズムのソースコード オンラインで見つけることができます。
このアルゴリズムは Ahoのコンパイラ:原則、技法、およびツール でも説明されていますが、実装の詳細については説明がまばらです。また、 Cでのトンプソン構造の実装 から学ぶこともできます。優れたラスコックスは、 正規表現の一致 に関する人気記事で詳細を説明しました。
以下のGitHubリポジトリで、Javaトンプソンの構築の実装を見つけることができます。最初に正規表現からNFAが作成され、次に入力文字列がそのNFAと照合されます:
https://github.com/White-White/RegSwift
退屈な言葉はもうありません。このレポを確認してください。正規表現をNFAに変換し、NFAの状態遷移を視覚的に示します。