Sep 09, 2013

Perl で grep.pl

UNIX/Linux のコマンドに lv/lgrep というのがあります。ぽちは UTF-8 や CP932、EUC-JP や 7bitJIS の各日本語文字エンコーディングに跨ってテキストファイルの中身を検索するのに使っています。この lgrep を、ぽちが普段使う機能の範囲だけ、Windows上の Emacs を通して使えるように、Perl で書いてみました。

grep.pl

#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use Encode qw/ encode decode /;
use Encode::Guess qw/ euc-jp cp932 iso-2022-jp utf8 /;
use Encode::Locale;
use Getopt::Std;

my %opts;
getopts 'n', \%opts;

my $expr = decode 'console_in', shift @ARGV;
my @trg = map { glob } @ARGV;

for my $file ( @trg ) {
    -f $file or next;
    open my $fh, '<', $file or die "Couldn't open $file: $!";
    my $str = join '', <$fh>;
    close $fh;
    $str or next;

    my $encobj = Encode::Guess->guess( $str );
    my $enc;
    unless ( ref $encobj ) {
        $enc = 'utf8';
        warn "Couldn't guess: $encobj. $file is decoded by $enc.\n";
    } else {
        $enc = $encobj->name;
    }
    my @decoded =  split "\n", decode $enc, $str;

    my ( $i, @linum, @greped, @maped );
    for my $line ( @decoded ) {
        ++$i;
        if ( $line =~ /$expr/g ) {
            push @greped, $line;
            push @linum, $i;
        }
    }

    for my $greped ( @greped ) {
        my $linum = shift @linum;
        if ( $#trg > 0 ) {
            if ( $opts{ n } ) {
                push @maped, "$file:$linum:$greped";
            } else {
                push @maped, "$file:$greped";
            }
        } else {
            if ( $opts{ n } ) {
                push @maped, "$linum:$greped";
            } else {
                push @maped, $greped;
            }
        }
    }

    my $encoded = encode 'console_out', join "\n", @maped;
    print $encoded, "\n" if $encoded;
}

__END__

使い方はこんな感じ。

C¥> perl grep.pl -n 金剛 kiniro_mosaic_utf8.txt kongou_mosaic_euc-jp.txt kan_colle_cp932.txt sasebo_kaigunbochi_7bitjis.txt
kongou_mosaic_euc-jp.txt:3:英国生まれの金剛デース!!
kan_colle_cp932.txt:7:金剛 「Hi!今日も良い天気ネー!」
sasebo_kaigunbochi_7bitjis.txt:14:地元住民には海軍墓地として知られる佐世保市東公園には、金剛・加賀・飛龍・瑞鳳・大鷹・矢矧の慰霊碑が存在する。

第一引き数には正規表現を受け取るので、正規表現のメタ文字が含まれる文字列をそのままの形で検索したい場合には、メタ文字をバックスラッシュでエスケープしてあげて下さい。

Posted at 12:59 in perl | Comments/Trackbacks ()
Comments/Trackbacks
TrackBack ping me at
http://pochi.usamimi.info/blog/perl/grep.
Post a comment

writeback message: