Perl Perl_5
Perl grep 基礎 (0x277)

目次 - Perl Index
Theme
Perl について、復習を兼ねて断片的な情報を掲載して行く連載その 0x277 回。
Perl で、任意のデータリストから任意のデータのみを取り出す関数「 grep 」を確認する。
システムコマンド「 grep 」
Unix 系システムには「 grep 」( グレップ ) と呼ばれる有名なコマンドがあります。
「 man grep 」によれば、システムコマンド「 grep 」の書式は、次のように解説されています。
grep [options] PATTERN [FILE ...]
grep [options] [-e PATTERN | -f FILE] [FILE ...]
コマンド「 grep 」は、 引数「 FILE 」に指定したファイルの中から「 PATTERN 」にマッチした行を取り出すことが出来ます。
例えば、ファイル名「 file.txt 」の中から、文字列「 Hello 」を含む行を取り出したい場合はシェル上で次のように「 grep 」を実行します。
grep Hello file.txt
「 PATTERN 」の部分には「 正規表現 」も利用出来ます。
通常「 grep 」の正規表現では、「 Basic Regular Expression 」(BRE : 基本正規表現 ) のみが利用可能ですが、「 grep 」の実装によっては「 Extended Regular Expression 」( ERE : 拡張正規表現 ) を利用することが出来ます。
# BRE
grep 'Hel\{1\}o' file.txt
# ERE
grep -E 'Hel{1}o' file.txt
grep -E 'Hel+o' file.txt
ちなみに、コマンド「 grep 」の名前は、古のラインエディタ「 ed 」のコマンド「 g/re/p 」に由来するそうです。
エディタ「 ed 」は、僕が普段利用しているエディタ「 vi 」 ( Vim ) にも大きな影響を与えていて、vi の「 ex コマンド 」のベースになっている ( というか vi のプロトタイプ的な ) ラインエディタ「 ex 」の直系 ( ? ) の先祖です。詳しくは、grep - Wikipedia あたりを参照します。
Perl の関数「 grep 」
Perl にも例のごとく、システムコマンドと同名の関数「 grep 」が用意されています。
Perl の関数「 grep 」でも正規表現パターンを利用することが出来ますが、Perl の正規表現は拡張正規表現よりもさらに拡張された利便性を持っています。
Perl の正規表現について確認した項目は、こちら ( index ) でまとめました。
grep - perldoc.jp によれば、Perl の関数「 grep 」の書式は次のものです。
grep BLOCK LIST
grep EXPR, LIST
Perl の「 grep 」では、「 LIST 」に指定したリストデータをひとつずつ取り出して「 BLOCK 」または「 EXPR 」で評価し、リストコンテキストの場合は結果が 真 だったもののリストを返します。
スカラコンテキストで「 grep 」を利用した場合は、評価の結果が 真 だったものの個数を返します。
関数「 grep 」を利用する
Perl の組み込み関数「 grep 」を利用してみます。
ここではまず、いくつかの行を持ったファイル「 file.txt 」を読み込みます。それから、配列変数に格納したそれらの各行を「 grep 」します。
ファイルのをオープンする際には、予め use してあるプラグマ「 autodie 」(0x276) によって関数「 die 」の記述を省いています。
書式は「 grep BLOCK LIST 」を採用しています。
use strict;
use warnings;
use autodie;
open my $fh, '<', 'file.txt';
chomp(my @arry =<$fh>);
print "--- before grep! ---\n";
foreach (@arry) {
print "$_\n";
}
# grep BLOCK LIST
my @match = grep { /hel+o/i } @arry;
print "--- after grep! ---\n";
foreach (@match) {
print "$_\n";
}
上記プログラムを実行すると以下の結果を得られます。
--- before grep! ---
Hello world.
goodbye world.
Hello file.
goodbye file.
--- after grep! ---
Hello world.
Hello file.
関数「 grep 」のパターン「 /hel+o/i 」にマッチングした行のみが配列変数「 @match 」に格納されていることがわかります。
書式「 grep EXPR, LIST 」を採用して次のように記述しても同じ結果が得られます。
grep /hel+o/i, @arry;
関数「 grep 」は、その評価対象をお馴染みのスカラ変数「 $_ 」としています。
「 foreach 」制御構造等「 $_ 」を扱う他の多くの構文と同じく、「 $_ 」の値を変更すると元のデータも変更してしまうので注意が必要です。
my @arry = qw/1 2 3 4/;
print "\@arry: @arry\n";
my @product = grep { $_ *= 2 } @arry;
print "\@arry : @arry\n";
print "\@product : @product\n";
上記を実行すると次の結果が得られます。
@arry: 1 2 3 4
@arry : 2 4 6 8
@product : 2 4 6 8
元の値を格納していた配列変数「 @arry 」の値が変更されていることがわかります。
簡潔に「 grep 」を利用する。
前項で確認した次のコードでは、読み込んだファイルの内容を配列変数「 @arry 」に格納してから、パターン「 /hel+o/i 」を含む行を関数「 grep 」で取り出しています。
use strict;
use warnings;
use autodie;
open my $fh, '<', 'file.txt';
chomp(my @arry =<$fh>);
print "--- before grep! ---\n";
foreach (@arry) {
print "$_\n";
}
# grep BLOCK LIST
my @match = grep { /hel+o/i } @arry;
print "--- after grep! ---\n";
foreach (@match) {
print "$_\n";
}
関数「 grep 」の引数には「 LIST 」データを指定出来るので、実際には、上記コードのファイルハンドル「 $fh 」を、次のように直接「 grep 」の引数に指定することも出来ます。もちろんダイヤモンド演算子 (0x226) と一緒にです。
my @match = grep { /hel+o/i } <$fh>;
0x277 -> 0x278 へ
次回は、今回の「 grep 」と似た書式をもった Perl の組み込み関数「 map 」を確認します。
参考情報は書籍「 初めての Perl 第 6 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。
目次 - Perl Index
Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)