ANDやORを用いた検索式でテキスト走査する(perl)
2012-01-26-1
[Programming]
ANDやORなどを用いた検索式でgrepのようなテキスト走査するタスク。
検索式に用いる演算子は AND→"&", OR→"|", NOT→"!" と括弧"()"。
具体例を挙げる。
検索式「(あい|うえ)&お&!(か|き|け)」とマッチするものしないもの。
- あいうえお → o
- ああいおお → o
- おうえい → o
- うえおけ → x
- あいうえおけ → x
■コード(logrep.pl):
■実行例:
検索式中の文字列を入力テキストにマッチするか否かで1か0に置き換え、そのまま論理式として eval する手軽ながら強引な手法。
例えば「ああいおお」が入力で与えられると、検索式「(あい|うえ)&お&!(か|き|け)」は論理式「(1|0)&1&!(0|0|0)」に変換される。これは1になるのでマッチ判定となる。なお、エスケープ処理してないので活用時には要修正。eval は Web で使うとセキュリティホールになるので要注意。
ちなみにAND検索は正規表現の「肯定先読み」で実現できるが、今回のようなタスクにはちょっと面倒。肯定先読み正規表現によるAND検索の例:
ref.
- [を] 転置インデックスの構成とブーリアン検索[2008-01-18-1]
- [を] Perl の utf8 まわりのおまじない[2009-09-12-4]
- [を] Perl の -T スイッチ[2006-05-27-3]
検索式に用いる演算子は 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]