#!/usr/bin/perl
use 5.001 ; use strict ; use warnings ;
use Getopt::Std ; getopts ':!=c:e:f:quvy1' , \my%o ;
use Encode qw/decode_utf8 encode_utf8/ ;
use Term::ANSIColor qw/:constants/ ; $Term::ANSIColor::AUTORESET = 1 ;
use FindBin qw[ $Script ] ;
sub main ;
main () ;
exit 0 ;
# メインの部分の処理
sub main ( ) {
sub init ( ) ;
sub Select ( );
sub LineProc ( $ ) ;
sub Match ( ) ;
our $search ;
our $lineproc ; # どういう処理をするかを、init関数の中で定義する。
our %words ; # 検索パターンを複数。
our $flip ; # 反転するかどうか $o{v} と真偽は 一致
our $col ; # どの列を検索するか。 -cの指定が1始まりであるのとは異なり、0始まり
our @cols ;
our $cstr ;
our $isep = "\t" ; # <-- 指定可能とすることはあり得る。
init () ;
my $oL ; # 条件に適合したので、出力をした行数
my $tL ; # 読み込んだ行数
while ( <> ) {
chomp ;
Select () ; # $cstr が操作されていることに注意。$_ から部分列を きりだす。
$oL += LineProc Match ;
$tL ++ ;
}
#my $mL = $o{v} ? $tL - $oL : $oL ; # 条件にあった数。ただし、-v により条件を反転させる。
print STDERR CYAN sprintf "match:%d unmatch:%d total:%d ($Script)\n",$oL,$tL-$oL,$tL unless $o{q} ;
return ;
sub init ( ) {
sub build_range ( ) {
my @ranges = split /,/ , $o{c} // '' , -1 ;
grep { $_ = $_ . ".." . $_ unless m/\.\./ } @ranges ; # <--
do { m/^(.+)\.\.(.+)/ ; push @cols , map { $_ > 0 ? $_ - 1 : $_ } $1 .. $2 } for @ranges ;
}
$| = 1 if $o{'!'} ;
#$col = $o{c} > 0 ? $o{c} - 1 : $o{c} if exists $o{c} ; # 負の数であれば、末尾から列位置を数えることになる。
build_range ( ) ;
$col = $cols[0] ;
$flip = $o{v} ? 1 : 0 ;
# 行全体から文字列を切り出す関数
sub Select0 { $cstr = $_ } ;
sub Select0u { $cstr = decode_utf8 $_ } ;
sub Selectc { $cstr = [split/$isep/,$_,-1]->[$col] } ;
sub Selectcu { $cstr = decode_utf8 [split/$isep/,$_,-1]->[$col] } ;
sub SelectC { $cstr = join $isep, @{[split/$isep/,$_,-1]}[@cols] } ;
sub SelectCu { $cstr = decode_utf8 join $isep, @{[split/$isep/,$_,-1]}[@cols] } ;
* Select = * Select0 ;
* Select = * Select0u if $o{u} ;
* Select = * Selectc if @cols == 1 ;
* Select = * Selectcu if @cols == 1 && $o{u} ;
* Select = * SelectC if @cols >= 2 ;
* Select = * SelectCu if @cols >= 2 && $o{u} ;
# マッチの判定をする関数
sub matchP { $cstr =~ m/$search/ } ;
sub matchN { $cstr !~ m/$search/ } ;
sub matchEP { $words { $cstr } } ;
sub matchEN { $words { $cstr } ? 0 : 1 } ;
* Match = * matchP ;
* Match = * matchN if $flip ;
* Match = * matchEP if $o{1} ;
* Match = * matchEN if $flip && $o{1} ;
# 下記の関数は printもするし、個数も返す。
sub L0 { if ($_[0]) { print encode_utf8($_) , "\n" ; return 1} else { return 0 } }
sub Ll { if ($_[0]) { print "$.:\t" , encode_utf8($_) , "\n" ; return 1} else { return 0 } }
sub Ly { my $y = $_[0] ? 1 : 0 ; print "$y\n" ; return $y }
sub Lly { my $y = $_[0] ? 1 : 0 ; print "$.:\t$y\n" ; return $y }
* LineProc = * L0 ;
* LineProc = * Ll if $o{':'} ;
* LineProc = * Ly if $o{'y'} ;
* LineProc = * Lly if $o{':'} && $o{'y'} ;
# 検索する正規表現の構成
$search = decode_utf8 $o{e} if exists $o{e} ;
if ( defined $o{f} ) {
open my $fh , '<' , $o{f} or die "File `$o{f}' including the search words missing. " , $! ;
while ( <$fh> ) { chomp ; $words{ decode_utf8( $_ ) } = 1 } ; close $fh ;
$search = join '|' , keys %words ;
}
if ( $o{'='} ) {
my $header = <> ;
print "=:\t" if $o{':'} ;
print ! $o{y} ? $header : "=\n" ;
# $. = 0 ; # <- 他のコマンドと一致ないし整合性を図る必要がある。
}
}
}
# 主にコマンドの引数の部分の処理
# ヘルプの扱い
sub VERSION_MESSAGE {}
sub HELP_MESSAGE {
use FindBin qw[ $Script ] ;
my ($a1,$L,$opt,@out) = ($ARGV[1]//'',0,'^o(p(t(i(o(ns?)?)?)?)?)?$') ;
open my $FH , '<' , $0 ;
while(<$FH>){
s/\$0/$Script/g ;
$out[$L] .= $_ if s/^=head1\s*(.*)\n/$1/s .. s/^=cut\n//s && ++$L and $a1 =~ /$opt/i ? m/^\s+\-/ : 1 ;
}
close $FH ;
print $ENV{LANG} =~ m/^ja/ ? $out[0] : $out[1] // $out[0] ;
exit 0 ;
}
=encoding utf8
=head1
$0 -e regex
指定した列に指定した正規表現が合致する場合に、その行全体を出力する。
主要な動作の後に、標準エラー出力に処理した行数などを出力。
$0 -c 列番号 -e 正規表現 # 最も想定されている使い方。
$0 -c 列番号 -f ファイル名 # ファイルの各行に検索したい正規表現があると見なされる。
$0 正規表現 # 列を指定しないで、行全体からマッチすれば、その行を出力
$0 -v -c 列番号 -e 正規表現 # -v の指定により、マッチしない行を出力する。
オプション :
-c num : 検索対象を探す列を1個指定する。最左列は1、最右列は-1であり、右に向かうほど1ずつ増加。
-e str ; 正規表現の指定。grep と違って1回のみ。
-f filename : 検索する正規表現が含まれているファイルの指定。各行がOR条件で検索されることになる。
-1 ; -f と共に用いる。ファイル filename の各行のどれかと指定列が一致するもののみを取り出す。高速のはず。
-u ; 文字列の比較は utf8で行う。
-v : 行の選択が反転する(マッチしない行が選択される)。
-y : マッチするかどうかで 1/0のみ各行に出力する。
-q : 何行マッチした、などの付加情報を標準エラー出力に出力しない。
-= ; 先頭行をヘッダと見なし、これに応じた処理をする。
-: ; データの番号を出力する。
開発メモ:
* Colgrep がutf8に対応していない colgrep -= -c1 -e '^6307' 1504*c1.csv
=cut
=head1 NAME
$0 - pattern searcher given which column to seek together with regular expression
SYNOPSIS
$0 -c $col_num -e $regex # The most usual usage
$0 -c $col_num -f $filename
$0 -e $regex
$0 -v -c .. .. # unmatch ; reverse the matching condition.
OPTIONS
You can specify the options which appears as follows .
-c number
Specify the column number. Note that the leftest column is numbered as 1.
-f filename
The file specified by filename is regarded to contain elements separated
by line breaks each of which are to specify the pattern to be matched.
=cut
=for comment
changeset: 318:85a987ce61ff
user: Toshiyuki Shimono
date: Mon Mar 07 20:00:34 2016 +0900
summary: --help で --help opt でオプション指定だけのヘルプを表示する様にした。このことはヘルプの本文に記載していない。また、$ARGV[1]未定義警告が出る可能性が残っている。
=for comment
changeset: 285:f6fef6826533
user: Toshiyuki Shimono
date: Wed Mar 02 14:51:45 2016 +0900
summary: いくつかのファイルを改名
=for comment
changeset: 268:31b37274f835
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Fri Feb 26 07:51:05 2016 +0000
summary: colgrep.pl マニュアルの編集
=for comment
changeset: 266:3318723ff27e
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Fri Feb 26 07:34:14 2016 +0000
summary: colgrep.pl edited online with Bitbucket
=for comment
changeset: 265:7c3930e1a0d5
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Thu Feb 25 08:38:58 2016 +0000
summary: colgrep.pl edited online with Bitbucket
=for comment
changeset: 264:388169015481
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Thu Feb 25 08:37:14 2016 +0000
summary: colgrep.pl に -y情報を付加。そして、カラーで処理行数など標準エラー出力に出力するようにした。
=for comment
changeset: 261:25d722a70050
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Thu Feb 25 06:10:26 2016 +0000
summary: colgrep.pl の使い方がわかるようにマニュアルを書いた。
=for comment
changeset: 242:69fc8767704f
user: Tulamili
date: Sat Feb 20 16:01:35 2016 +0900
summary: colgrep デバグ
=for comment
changeset: 241:4a44f1bf06c0
user: Toshiyuki Shimono <tulamili@gmail.com>
date: Fri Feb 19 13:27:53 2016 +0000
summary: colgrep.pl created
=cut