www.forefrontier.co.jp

正規表現パート2
NFAエンジンの場合は、
正規表現の磨き上げが必要?
覚えていないと思うので・・・おさらい
まずは、
DFA(テキスト主導型)エンジン
バックトラックが持つ効率の悪さを回避する為に
全ての可能性のあるマッチを同時に管理することによって、高速処理を実現するエンジン
管理用のマップを作るため、場合により時間がかかり、メモリが必要になる
語ると長いのでざっくりNFA
NFA(正規表現主導型)エンジン
バックトラックを根幹にもつエンジン
*POSIX NFA
最長のマッチを返さなくてはならない
*従来型NFA
正規表現主導型の性質を利用して、どのようなマッチを望むか性格に指定できる
※ 覚える必要はないですが・・・
記憶のない人は、前回の資料を見て下さい。
バックトラックと効率化
バックトラック機能のあるNFAエンジンの場合
選択肢が発生した場合、その位置に戻れるよう
ぱんくずのように戻り位置を記録していく方法を採用している
分かりにくいので例を次に示します。
つまり
斜めの線の→が入っている箇所が
選択によるバックトラックが発生する位置
バックトラックが多いですね。
もしかして・・・バックトラック減らしたら効率化?
こうしたら、バックトラック減らせる?
減らせそうですが・・・どうでしょう?
考えるべきこと
変更によってメリットがあるか否かは
以下を考える必要があります。
エンジンの違いによって得られる効果は同じか
この変更が効果をはっきするのは、どんなときか
結論1
エンジンタイプによる効果のちがい
POSIX NFAエンジンタイプ
この変更による効果はほとんどありません。理由は、正規表現が方言できる全ての順列が試さ
従来型NFA
すぐにマッチに結びつくような選択肢の並べ方をすれば、最初のマッチが見つかったところで
結論2
マッチ結果による効果の違い
この変更によって処理がはやくなるのは、マッチが有る時だけに限られます。従来型NFAがマ
よって、最終的にマッチ不成功になったからには、全ての順列を試し済みなので、順番を変え
まとめ
NFAエンジンの場合
マッチするパターンにおいて、バックスラッシュの回数を減らすことはパフォーマンス向上に
さらに良い方法とは
文字のひとつひとつを反復処理(循環処理)しなければならない。ここにオーバーヘッドがか
この部分を削減できれば、効率手的な正規表現となる。
ではどうするか・・・
さらに、もっと良い方法
元々(上段)を下段のように変更するとバックスラッシュを抑えることができる
「[^\\”]」は、通常の文字列にマッチするので
「[^\\”]+」を使えば、(...)*の1回分で1度に読める通常の文字をまるまる読み込める
→バックトラックを削減し、スターによる反復処理も最小限!
話は飛びますが・・・
正規表現にはいろいろな書き方があるお話は前回しました。
例えば a, b, c, d, e, f, g のどれかに一致する文字は、
[a-g] という文字クラスを使う方法のほか
a|b|c|d|e|f|gという書き方もできますね。
さて・・・どっちが早いのでしょう?
そうだ、ベンチマークテストをやってみよう!
正規表現のベンチマークテスト方法
そもそもベンチマークテストとは?
→ ある仕事を行うのにどれくらい時間がかかるかを単純に計測すること
時間計測のためにすることは?
システム時間を取得し、問題の処理を実行し、再度システムの時間を取得する
この最初に取得したシステム時間と、次に取得したシステム時間のさが処理に要した時間とな
計測時の注意点
計測したい仕事の時間だけを計測する
十分な仕事を実行する
(コンピュータが優秀すぎると比較できない)
正しい仕事を実行させる
(オーバーヘッドを増やさない)
ベンチマークに使うコード(PHP版)
$TimesToDo = 1000;
// テスト文字列の準備
$TestString = "";
for ($i = 0; $i < 1000; $i++)
{
$TestString .= "abababdedfg";
}
// 最初のテストの実行
$start = gettimeofday();
for ($i = 0; $i < $TimesToDo; $i++)
{
preg_match('/^(a|b|c|d|e|f|g)+$/, $TestString);
}
$final = gettimeofday();
$sec = ($final['sec'] + $final['usec']/1000000) ($start['sec'] + $start['usec']/1000000);
print("Alternation takes %.3f seconds\n", $sec);
// 第二のテストの実行
実際、自分では計測していませんが
環境にもよりますが
以下のような結果がでたそうです。
Alternation takes 27.404 seconds
Character class takes 0.288 seconds
ずいぶん違いますね。
なぜ?
「a|b|c|d|e|f|g」は、1つの開始位置で必ず7文字分のバックトラックが必要となり、マッチに
「[a-g]」は、次の位置でマッチするまで、1文字分前進のバックトラックしか発生させない為
正規表現の処理の高速化には、他にも色々ありますが、選択はNFAエンジンの場合、必ずバッ
Fin
皆さん、用法用量を正しく守って使いましょう。