古い記事
ランダムジャンプ
新しい記事
ANDやORなどを用いた検索式でgrepのようなテキスト走査するタスク。
検索式に用いる演算子は AND→"&", OR→"|", NOT→"!" と括弧"()"。

具体例を挙げる。
検索式「(あい|うえ)&お&!(か|き|け)」とマッチするものしないもの。
- あいうえお → o
- ああいおお → o
- おうえい → o
- うえおけ → x
- あいうえおけ → x

■コード(logrep.pl):
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
use utf8;
use open ':utf8';
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my $query = shift @ARGV;
$query = Encode::decode_utf8($query) if not utf8::is_utf8($query);

my %token;
foreach my $i (grep {not /^\s*$/} split(/[\(\)\&\|\!]+/, $query)) {
    $token{$i} = 1;
}

while (<>) {
    my %match;
    foreach my $i (keys %token) {
        $match{$i} = 1 if /$i/;
    }
    my $pat = $query;
    $pat =~ s/([^\(\)\&\|\!]+)/$match{$1}?1:0/ge;
    print if eval "$pat";
}

■実行例:
% cat test.txt
あいうえお
ああいおお
おうえい
うえおけ
あいうえおけ
% ./logrep.pl '(あい|うえ)&お&!(か|き|け)' test.txt
あいうえお
ああいおお
おうえい

検索式中の文字列を入力テキストにマッチするか否かで1か0に置き換え、そのまま論理式として eval する手軽ながら強引な手法。

例えば「ああいおお」が入力で与えられると、検索式「(あい|うえ)&お&!(か|き|け)」は論理式「(1|0)&1&!(0|0|0)」に変換される。これは1になるのでマッチ判定となる。なお、エスケープ処理してないので活用時には要修正。eval は Web で使うとセキュリティホールになるので要注意。

ちなみにAND検索は正規表現の「肯定先読み」で実現できるが、今回のようなタスクにはちょっと面倒。肯定先読み正規表現によるAND検索の例:
perl -ne 'print if /^(?=.*abc)(?=.*xyz)/'
abcddddxyz → o
xyzzzzabcd → o
abcdefghij → x
qrstuvwxyz → x

ref.
- [を] 転置インデックスの構成とブーリアン検索[2008-01-18-1]
- [を] Perl の utf8 まわりのおまじない[2009-09-12-4]
- [を] Perl の -T スイッチ[2006-05-27-3]