私は現在、特定の入力に対して一致すると指数関数的に実行される可能性がある正規表現の問題を調査し(a*)*
て(a|a)*
います。一致した文字列の場合、文字列の一致を試みるのに必要な時間が 2 倍になります。これは、PCRE で使用されているような、失敗する前にツリー内のすべての可能な分岐を試行するバックトラッキング/NFA アプローチをエンジンが使用する場合にのみ当てはまります。
私の質問は、なぜ(a?)*
脆弱でないのですか? バックトラッキングに関する私の理解に基づいて、文字列「aaaab」で何が起こるべきかは、基本的に(a|a)*
. 標準の Thomspson NFA 構造を使用して NFA を構築する場合、確実に発生する各イプシロン遷移に対して、エンジンはそれらを取り続け、2 つの a の場合と同じ方法でバックトラックする必要がありますか? 例 (いくつかの手順を省略し、@ がイプシロンに置き換わる場所):
"aaaa" は一致するが、'b' には一致しない、失敗 (バックトラック)
"aaaa@" は一致、'b' は失敗 (バックトラック)
"aaa@a" は一致、'b' は失敗 (バックトラック)
"aaa@a@ " 一致、'b' 失敗 (バックトラック)
...
"@a@a@a@a@" 一致、'b' 失敗 (バックトラック)
イプシロンと a のすべての可能な組み合わせを試してみると、確実にルートが指数関数的に爆発的に増加しますか?
NFA からイプシロン遷移を削除することは理にかなっていますが、これには(a*)*
パターンからすべての非決定論を削除する効果があると思います。ただし、これは間違いなく脆弱であるため、何が起こっているのか完全にはわかりません!
事前にどうもありがとうございました!
編集: NFA が従来のバックトラッキングでトラバースされた場合、イプシロンがまだ存在できないことが Qtax によって指摘されています。それ以外の場合(@)*
は、永久に一致しようとします。では、どの NFA 実装が指数関数的になり、(a*)*
そうではない可能性があるのでしょうか? これが本当に質問の核心です。(a|a)*
(a?)*