
「最初はうまくいかない場合は、もう一度やり直してください」という格言は、パターンマッチングと呼ばれるプロセスで形式化されます。バックトラック。バックトラッキングは、マッチャーが一致する可能性のあるすべての可能な組み合わせをチェックする方法です。この投稿では、JMPのパターンマッチャーのいくつかの秘密の機能を使用して、バックトラッキングプロセスを公開しています。 以下の1つのステートメントは、適度に複雑なパターンマッチです。ただし、単純な一致(および正規表現)でもバックトラックを使用します。
シークレット1:21行目のLog()関数は、JMPログウィンドウに出力を生成します。 >>は、以前に一致したテキストを取得して印刷する前に、ソース内のゼロベースの位置と提供されたテキストラベルとともに表示します。 これはバックトラックとは何の関係もなく、デバッグとはすべて関係があります。 このシークレットを使用して、独自のパターンをデバッグできます。
シークレット2:PatTest()には3つの引数がありますが、これまでに使用されたのは1つだけです。 これはすべてバックトラックについてです。 2番目の引数のJSLは順方向に実行され、3番目の引数のJSLは後方向に実行されます。
秘密3:PatMatch()は通常、可能な限り失敗を最適化します。 パターンの残りの最小長に一致するのに十分なテキストがソース文字列に残っていないことがわかると、停止します。 FULLSCANオプションは、その最適化をオフにします。 この例では、FULLSCANオプションがないと、バックトラックが途中で停止するように見えます。
シークレット4:PatFail()を使用して、各一致を強制的に失敗させ、代替案を検討することで、可能なすべての一致を見つけることができます。
以下に説明付きのコードと出力を示します。
Pat Match(
"EDACGDE", // a contrived string to exercise backtracking
(
Pat Len( 1 ) >> p // match a character, store in p
+
Pat Test(
p > "B", // test
Write( "p=", p, " " ), // advance
Write( "retry\!n" ) // backtrack
)
+
Pat Arb() // skip zero or more characters
+
Pat Len( 1 ) >> q // match another, store in q
+
Pat Test(
p < q & q < "F", // test
Write( "q=", q, " " ), // advance
Write( "retry " ) // backtrack
)
) >> Log( "FOUND" ) // a debugging tool
+
Pat Fail(), // try alternatives
NULL, // no replacement
FULLSCAN // to the bitter end
);
p = E q=D再試行q=A再試行q=C再試行q=G再試行q=D再試行q=E再試行再試行
p = D q=A再試行q=C再試行q=G再試行q=D再試行q=E
1(FOUND)DACGDE
再試行再試行
p=再試行
p = C q=G再試行q=D
3(FOUND)CGD
q=Eを再試行します
3(FOUND)CGDE
再試行再試行
p = G q=D再試行q=E再試行再試行
p = D q = E
5(FOUND)DE
再試行再試行
p=E再試行
0
説明
まず、最後のゼロ。 これがリターンコードであり、一致が失敗したことを示しています。 実際の試合見つかった4つの一致がありましたが、PatFail()によって別の一致が検索されました。 これは予想されます。
次に、PとQ。 pはEから始まり、>Bのテストは満足です。 PatArb()は消極的で、最初は何もスキップしません。 qはEに続くDを取得します。 しかし、今回のテストは不幸です。 pと「F」の間のqは真ではありません。 バックトラックする時間です! Dをqに入れるLEN(1)は、Dを戻し、PatArb()は別のことをする機会を与えられます。 今回はしぶしぶ1人のキャラクター、Dを取ります。 次に、PatLen(1)はAをqに与えます。 最初の行の終わりに、2回の再試行があります。 2番目はp用です。 次の行は、pが2番目の文字Dを取得していることを示しています。パターン一致は固定されていないため、一致の開始は、バックトラッキングプロセスの一部としてテキスト内を前方にフロートすることができます。今回の試合は、最初の成功が起こるまで、PatArbがどんどん進んでいきます。 >> Log( "FOUND")は成功をログに記録し、PatFail()はバックトラックを続行させます。
明確でない場合は、より簡単なテストを試して、>> LOG( "tag")メソッドを使用してそれらを計測し、何が起こっているのかを把握することができます。
この時点で、この試合が非常に長い間実行される理由は明らかです。

aaaa ... aaaの文字列にはbがないため、成功しない可能性がありますが、マッチャーは、2文字をスキップし、次に3をスキップし、3をスキップするという愚かな組み合わせをたくさん試すことによってそれを発見する必要があります。続いてスキップ2...などなどなど... バックトラッキングでは、不適切に記述されたパターンを修正することはできません。 そのプログレスバーは、ほぼ終了したことを意味するものではありません。 (このダイアログを表示する場合を除いて、patrepeat内にpatarbを配置する理由はありません。 Patarbはすでに任意の数の文字と一致しています。)
2017年2月1日更新-新しいコミュニティのフォーマットを修復します。