5部 関数リファレンス

study

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;
} 

foよりもめずらしいので、/\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";
} 

関連記事