study SCALAR
study
は、パターン・マッチを行う前に、パターンを学習する関数です。これは、検索のために、どのようなパターンを何回使うかによって、また、検索される文字列内の文字頻度の分布によって、時間を節約することになるかもしれませんし、逆に浪費することになるかもしれません。予習をした場合と、しない場合の実行時間を比較して、どちらが速いか調べることが、必要でしょう。短い固定文字列 (複雑なパターンの固定部分を含みます) をたくさん検索するループで、もっとも効果があるでしょう。
一つの時点では、一つのstudy
だけが有効です。別のスカラをstudy
した場合には、以前に学習した内容は忘却されてしまいます。
特定のパターンを含む行の前にインデクスを付けるエントリを入れる
while (<>) { study; print ".IX foo\n" if /\bfoo\b/; print ".IX bar\n" if /\bbar\b/; print ".IX blurfl\n" if /\bblurfl\b/; ... print; }
f
はo
よりもめずらしいので、/\bfoo\b/
を探すとき、$_
でf
を含む場所だけが探されます。一般にかなりの結果が得られます。
唯一の問題は、節約できる時間が、最初にリンクリストを作る時間よりも多いかどうかです。
実行時まで、探そうとする文字列がわからないときには、ループ全体を文字列として組み立てて、eval
すれば、いつも、ずべてのパターンを再コンパイルするという事態は避けられます。ファイル全体を一つのレコードとして入力するために、$/
を未定義にすれば、かなり速くなり、多くの場合fgrep(1)
のような専用のプログラムより速くなります。
以下の例は、ファイルのリスト (@files
) から単語のリスト (@words
) を探して、マッチするものがあったファイル名を出力します。
$search = 'while (<>) { study;'; foreach $word (@words) { $search .= "++$seen{$ARGV} if /\\b$word\\b/;\n"; } $search .= "}"; @ARGV = @files; undef $/; eval $search; $/ = "\n"; # 入力のデリミタをもとに戻す foreach $file (sort keys(%seen)) { print $file, "\n"; }