Fool Pool

ハマった記

マッチした部分のハイライト表示 in Perl

概要

入力ファイル中のパターンを検索し、マッチしたパターンをハイライト表示させる

実行例)
[sample.in]

吾輩わがはいは猫である。名前はまだ無い。
どこで生れたかとんと見当けんとうがつかぬ。
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
吾輩はここで始めて人間というものを見た。
しかもあとで聞くとそれは書生という人間中で一番獰悪どうあくな種族であったそうだ。

[実行結果]

$ perl code_highlight.pl 吾輩 sample.in 
pattern: 吾輩
1 patterns are matched (at line 1):  *吾輩* わがはいは猫である。名前はまだ無い。
1 patterns are matched (at line 4):  *吾輩* はここで始めて人間というものを見た。

仕様

  • 検索すべきパターンを第1引数に、入力ファイル名を第2引数に与える
  • パターンにマッチした行について、「行数」と「マッチした個数」、および「マッチした部分をハイライトした文字列」を表示する
  • 行中でマッチした部分は、「 *パターン* 」のようにハイライトする
  • マッチしなかった行は表示しない

実装

[code_highlight.pl]

#!/usr/bin/env perl
use 5.0100;

sub match_and_highlight {
    my ($pattern, $line) = (shift, shift);
    my $count = ($line =~ s/$pattern/ *$&* /g);
    ($count, $line); 
};

my $pattern = shift @ARGV;
my @raw_lines = <>;

my @lines = map {
    my $line = $_;
    chomp($line);
    $line;
} @raw_lines;

print "pattern: $pattern\n";

for (0 .. $#lines) {
    my $index = $_;
    my $line = $lines[$index];
    my ($count, $line1) = match_and_highlight ($pattern, $line);
    say $count . " patterns are matched (at line " . ($index + 1) . "): " . $line1 if $count;
}

解説

引数で与えたパターンで一行ずつパターンマッチをかける。まっちしたパターンの全文は $& で参照できる。または、全体をキャプチャグループ「()」で囲み、$1 で参照しても良い。

    my $count = ($line =~ s/($pattern)/ *$1* /g);

今回は例文が短かったので、最初にサンプルテキストの全文を読み込むようにしたが、サイズが大きくなると処理が遅くなる。サンプルテキストが大きい場合は、お決まりのwhile(<>)の書き方の方が良い。

...
my $pattern = shift @ARGV;
my $cnt = 0;

print "pattern: $pattern\n";
while (<>) {
    $line = $_;
    chomp($line);
    $index = $cnt++;
    my ($count, $line1) = match_and_highlight ($pattern, $line);
    say $count . " patterns are matched (at line " . ($index + 1) . "): " . $line1 if $count;
}