#!/usr/bin/perl -T use 5.008 ; use strict ; use warnings ; # 5.011 use Getopt::Std ; getopts '~i:=!d:0:h:np:rt:' , \my %o ; #use List::MoreUtils qw/any none/ ; use List::Util qw [ max ] ; use Encode qw/decode_utf8/ ; use Memoize ; use Data::Dumper ; use Term::ANSIColor qw[ :constants] ; $Term::ANSIColor::AUTORESET = 1 ; memoize ( 'sCols' ) ; # ã“ã®ãƒ—ãƒã‚°ãƒ©ãƒ ã«ç¾ã‚Œã‚‹ sCols 関数を高速化ã™ã‚‹ã€‚ $| = 1 if $o{'!'} ; my %cream ; # 列ã®ç•ªå·ã®é…åˆ—ã‚’æ ¼ç´ã™ã‚‹ã€‚ # $cream{p} 出力ã™ã‚‹ã‚ˆã†æŒ‡å®šã—ãŸåˆ—番å·ã®ç„¡åé…列 # $cream{d} 削除ã™ã‚‹ã‚ˆã†æŒ‡å®šã—ãŸåˆ—番å·ã®ç„¡åé…列 # $cream{h} å…ˆé ã«ç§»å‹•ã™ã‚‹ã‚ˆã†ã«æŒ‡å®šã—ãŸåˆ—番å·ã®ç„¡åé…列 # $cream{t} 末尾ã«ç§»å‹•ã™ã‚‹ã‚ˆã†ã«æŒ‡å®šã—ãŸåˆ—番å·ã®ç„¡åé…列 my $emp = $o{'0'} // '' ; ; # å˜åœ¨ã—ãªã„セルをå‚ç…§ã—ãŸã¨ãã«è¡¨ç¤ºã™ã‚‹æ–‡å—列 my %colNamePos ; # 列ã®åå‰ã‹ã‚‰ã€1å§‹ã¾ã‚Šã®åˆ—番をå‚ç…§ã™ã‚‹ my $isep = $o{i} // "\t" ; # 入力ã®åŒºåˆ‡ã‚Šæ–‡å— my $split_limit = $isep eq '' ? 0 : -1 ; # split ã§ä½¿ã†ã€‚split//ã¯LIMIT=0ã«ã—ãªã„ã¨ã€çµæžœã«ç©ºæ–‡å—列ã®å€¤ãŒæœ€å¾Œã«ç”Ÿã˜ã‚‹ my $osep = $isep eq '' && $o{n} ? ' ' : $isep ; # 出力ã®åŒºåˆ‡ã‚Šå & init ; # オプションã«ã¤ã„ã¦ã®å‡¦ç† & main ; # メインã®å‡¦ç† printColsMain exit 0 ; # åˆæœŸåŒ–処ç†ã®ç‚ºã®å±•é–‹ã®å‡¦ç† sub expand ( $ ) { # ã¾ãš コンマã§åˆ†å‰², # 次㫠.. を展開ã™ã‚‹ã€‚ # æœ€å¾Œã«æ£ã®æ•°ã¯ 1を引ã。 #print BRIGHT_BLUE Dumper ["cNP=",%colNamePos] ; return () if ! defined $_[0] ; my @gr = split /,/ , $_[0] ; # grain 穀物ã®ç²’ã®ã¤ã‚‚り。expandedも考ãˆãŸãŒã€ã‚¹ãƒšãƒ«é•·éŽãŽã€‚ my $l = scalar @gr ; for ( reverse 0 .. $#gr ) { if ( $gr [ $_ ] =~ m|(.+)\.\.(.+)| ) { # *末尾* ã‹ã‚‰æ•°å—を展開ã™ã‚‹ã€‚ my ($c1,$c2) = ($1,$2) ; if ( $o{'='} ) { $c1 = $colNamePos { $c1 } ; $c2 = $colNamePos { $c2 } } #; print "\$c1=$c1, \$c2=$c2\n" } ; splice @gr , $_ , 1 , ( $c1 <= $c2 ? $c1 .. $c2 : reverse $c2 .. $c1 ) ; } else { $gr[ $_ ] = $colNamePos { $gr[ $_ ] } if $o{'='} ; } } #print CYAN Dumper [@gr], Dumper ; #print CYAN join ", " , @gr ; #@gr = grep { $_ ne 0 } @gr ; # 0ã¯å–り除ã。$0 ㌠-ptdhã®å¼•æ•°ã«0を与ãˆã‚‹ã®ã¯ã€ãƒ˜ãƒ«ãƒ—ã®æŠ‘åˆ¶ãŒä¸»ç›®çš„ã¨ãªã‚‹ã€‚ grep { $_ = $_ - ( $_ > 0 ? 1 : 0 ) } @gr ; # 1å§‹ã¾ã‚Šã§ä¸Žãˆã‚‰ã‚ŒãŸåˆ—番å·ã‚’0å§‹ã¾ã‚Šã«ã™ã‚‹ã€‚ãŸã ã—ã€è² ã®æ•°ã¯å¤‰ãˆãªã„。 return @gr ; } # åˆæœŸåŒ–処ç†ã€‚コマンド引数ã®ã‚ªãƒ—ションã«ã¤ã„ã¦ã®å‡¦ç† ; 2個ã®é–¢æ•° sub init { if ( ! scalar grep { defined } @o{qw/p d h t n/} ) { *STDOUT= *STDERR ; &HELP_MESSAGE ; exit } } # 列数ã”ã¨ã«ã€ã©ã®åˆ—を見ã›ã‚‹ã‹ã®åˆ—番ã®ç„¡åé…列を返ã™ã€‚ sub sCols ( $ ) { sub none ( &@ ) { my $f = shift; foreach ( @_ ) { return 0 if $f->(); } return 1 ; } sub drop ( $@ ) { my$o = shift @_ ; return grep { my$x=$_;none{$x==$_} @_ } @{$o} } ; # [] my $W = $_[0] ; # å„行ã®ã€ã‚»ãƒ«(列) ã®å€‹æ•°ãŒä¸Žãˆã‚‰ã‚Œã‚‹ã€‚ $cream {p} = [ 0 .. $W - 1 ] if ! defined $o{p} ; my @p_ = @{ $cream{p} } ; my @d_ = @{ $cream{d} } ; my @h_ = @{ $cream{h} } ; my @t_ = @{ $cream{t} } ; $_ = $W == 0 || abs ($_) >= $W && ! $o{r} ? -1 : $_ % $W for @p_ , @d_ , @h_ , @t_ ; # -r指定ã§å˜ç´”ã«ã‚µã‚¤ã‚¯ãƒªãƒƒã‚¯ @p_ = drop \@p_ , @d_ , @h_ , @t_ ; @h_ = drop \@h_ , @d_ ; # -h,-tã§æŒ‡å®šã•れãŸåˆ—ã§ã‚‚ã€-dã§æŒ‡å®šã•れãŸã‚‚ã®ã¯æ¶ˆã™ã€‚。 @t_ = drop \@t_ , @d_ ; # my @out = (@h_ , @p_ , @t_) ; #print join ". " , @{ $cream{p}} , "#" ; # map ( $_ // "u" , @out, @{$cream{p}}) , "\n" ; if ( $o{'~'} ){ my @tmp = (-1) x ( 1 + max (@out , @{$cream{p}} ) ) ; # = map { $out[$_] } 0 .. $#out ; for ( 0 .. $#out ) { $tmp [ $out[$_] ] = $_ } @out = @tmp ; #print join ", " , map ( $_+1, @out) , "\n" ; } return [ @out ] ; } # å„行ã®å‡ºåЛ処ç†ã€‚ sCols関数を呼ã³å‡ºã—ã¦ã€é¸æŠžã™ã‚‹ã€‚-n ã§åˆ—番å·ã‚‚付ã‘る。 sub line ( ) { chomp ; $_ = decode_utf8 ( $_ ) if $isep eq '' ; # 入力ãŒSTDINã¨ã¯é™ã‚‰ãªã„ã®ã§ binmode を使ã‚ãš decode_utf8 my @F = split /$isep/ , $_ , $split_limit ; #use Data::Dumper ; print scalar @F , Dumper [@F]; @F = map { $_ + 1 . ":$F[$_]" } 0 .. $#F if $o{n} ; # -n ã§åˆ—番å·ã‚’コãƒãƒ³ã‚’付ã‘ã¦å‡ºåŠ› push @F , $emp ; # $F[-1] ã§å‚ç…§ã™ã‚‹ print join ( "$osep" , @F [ @{ sCols $#F } ] ) , "\n" ; } # main sub main { binmode STDOUT ,":utf8" if $isep eq '' ; # æ–‡å—å˜ä½ã§å‡¦ç†ã™ã‚‹å ´åˆã€utf8ã¨ã—ã¦ã®æ‰±ã„ã‚’ã™ã‚‹ã€‚ # 一行目ã‹ã¤ -= ãŒæŒ‡å®šã•れãŸå ´åˆã®å‡¦ç† if ( $o{'='} ) { $_ = <> ; chomp ; my $c = 0 ; $colNamePos { $_ } = ++ $c for split /$isep/ , $_ , $split_limit ; # <-- 分割文å—åˆ—ã«æ°—ã‚’ã¤ã‘ãŸã„ $cream{ $_ } = [ expand $o{$_} ] for qw/p d h t/ ; line ; # <-- - } else { $cream{ $_ } = [ expand $o{$_} ] for qw/p d h t/ ; } #print BRIGHT_GREEN Dumper [%colNamePos] ; # 引ãç¶šã処ç†ã€‚-=ãŒç„¡ã„å ´åˆã«ã¯ã€ã“ã“らã‹å§‹ã¾ã‚‹ã€‚ while ( <> ) { line } ; } ## ãƒ˜ãƒ«ãƒ—ã®æ‰±ã„ sub VERSION_MESSAGE {} sub HELP_MESSAGE { use FindBin qw[ $Script ] ; $ARGV[1] //= '' ; open my $FH , '<' , $0 ; while(<$FH>){ s/\$0/$Script/g ; print $_ if s/^=head1// .. s/^=cut// and $ARGV[1] =~ /^o(p(t(i(o(ns?)?)?)?)?)?$/i ? m/^\s+\-/ : 1; } close $FH ; exit 0 ; } =encoding utf8 =head1 csel -- Easier interface than cut/AWK to handle TSV/CSV input, with the options such as -p(Printing)/-d(Deleting)/-h(moving to Head)/-t(moving to Tail). AWK言語やコマンドcutã‚ˆã‚Šã‚‚åˆ—ã®æŠ½å‡ºã‚’ç°¡å˜ã«æ›¸ã‘るコマンドラインをæä¾›ã™ã‚‹ã€‚ 概è¦: TSVファイルç‰ã®æŒ‡å®šã•れãŸåˆ—を表示ã™ã‚‹ã€‚Specifying the column(s) by -p ã§è¡¨ç¤ºã™ã‚‹åˆ—を指定ã™ã‚‹ã€‚ for printing by -p -d ã§è¡¨ç¤ºã—ãªã„列を指定ã™ã‚‹ã€‚for hiding by -d -h ã§å…ˆé (å„行ã®å·¦éƒ¨åˆ†ã«è¡¨ç¤ºã™ã‚‹åˆ—を指定ã™ã‚‹ã€‚ for moving the leftmost by -h -t ã§æœ«å°¾(å„行ã®å³éƒ¨åˆ†ã«è¡¨ç¤ºã™ã‚‹åˆ—を指定ã™ã‚‹ã€‚ for moving the rightmost by -t 利用例 : $0 -p 5..9,2 -d 6..8 ; # 5列目ã‹ã‚‰9列目ã®å¾Œã«2列目を表示ã™ã‚‹ãŒã€ãŸã ã—6,7,8列目ã¯çœã。 $0 -p -1 ; # 最後ã‹ã‚‰1列目ã®ã¿ã‚’表示 ä»–ã®ã‚ªãƒ—ション : -= : データã®1行目ã«è¨˜è¼‰ã•れãŸåˆ—åã§æŒ‡å®šã™ã‚‹ã€‚-= を用ã„ãªã„å ´åˆã¯åˆ—指定ã¯ï¼Œå·¦ã‹ã‚‰ã®1ã‹ã‚‰å§‹ã¾ã‚‹ç•ªå·ã«ãªã‚‹ã€‚Utilizes the 1st line as a list of column names. -0 str : å˜åœ¨ã—ãªã„セルを指定ã—ãŸã¨ãã«è¡¨ç¤ºã™ã‚‹æ–‡å—列。未指定ã ã¨ç©ºæ–‡å—列。 -r : å˜åœ¨ã—ãªã„セルを指定ã—ãŸã¨ãã¯ã€ãã®æ™‚ã®å…¥åŠ›è¡ŒãŒæ¨ªã«ç„¡é™ã«å‘¨æœŸçš„ã«ã¤ãªãŒã£ã¦ã„ã‚‹ã¨ä»®å®šã—ã¦ã€æŒ‡å®šä½ç½®ã‚’å–り出ã™ã€‚ -i STRING ; 入出力ã®åŒºåˆ‡ã‚Šåã®æŒ‡å®šã€‚-i '' ã¨ã™ã‚‹ã¨ä¸€æ–‡å—ã”ã¨ã«å‡¦ç†ã€‚未指定ãªã‚‰ã‚¿ãƒ–æ–‡å—。 -n : 列ã«ç•ªå·ã‚’付与ã™ã‚‹ã€‚ -~ : 列ã®é †ç•ªã‚’逆転ã—ã¦ã€å…ƒã«æˆ»ã—ãŸã„時ã«ä½¿ã†ã€‚ $0 -t3 | $0 -~ -t3 ã®ã‚ˆã†ã«ä½¿ã†ã€‚5列ã«å¯¾ã—㦠$0 -~ -p3,4,2,1,5 ã®ã‚ˆã†ãªä½¿ã„方をã™ã‚‹ã€‚ --help : ã“ã® $0 ã®ãƒ˜ãƒ«ãƒ—メッセージを出ã™ã€‚ perldoc -t $0 | cat ã§ã‚‚ã»ã¼åŒã˜ã€‚ --help opt : オプションã®ã¿ã®ãƒ˜ãƒ«ãƒ—を出ã™ã€‚opt以外ã§ã‚‚ options ã¨å…ˆé ãŒ1æ–‡å—以上一致ã™ã‚Œã°è‰¯ã„。 補足 : - 列番å·ã¯å·¦ã®åˆ—ã‹ã‚‰æ•°ãˆã‚‹ã€‚1å§‹ã¾ã‚Šã§ã‚る。The leftmost column is numbered "1(one)". Not "0(zero)" - 列番å·ã‚’è² ã®æ•°ã§æŒ‡å®šã™ã‚‹ã¨ã€æœ«å°¾ã‹ã‚‰æ•°ãˆã‚‹ã€‚ The rightmost column is numbered "-1". - 範囲を指定ã™ã‚‹ã“ã¨ã‚‚ã§ãる。ãŸã¨ãˆã°ã€-p 2..5 ã¨ã™ã‚‹ã¨2列目ã‹ã‚‰5列目ã®ã¿è¡¨ç¤ºã™ã‚‹ã€‚ 5..2 ã¨ã™ã‚‹ã¨ã€é€†é †ã«ãªã‚‹ã€‚ ".." means range. 開発上ã®ãƒ¡ãƒ¢ : * -i ã®æŒ‡å®šã¯æ£è¦è¡¨ç¾ã¨è¦‹ãªã•れるãŒã€å…¥åŠ›ã®splitã«ã‚‚出力ã®join ã«ã‚‚用ã„ã‚‹ã®ã§ã€æ³¨æ„ãŒå¿…è¦ã€‚ * å¼•æ•°ã§æŒ‡å®šã§ãる列ã«é–¢ã—ã¦ã€ç¯„囲演算 .. ã«åŠ ãˆã¦ / ã§ä¸€å®šé•·ã®é£›ã³é£›ã³ã‚‚定義ã§ãるよã†ã«ã—ãŸã„。 * AWKã®ã‚³ãƒžãƒ³ãƒ‰ã‚’生æˆã™ã‚‹ã‚ˆã†ã«ã›ã‚ˆã€‚ ã“ã®ãƒ—ãƒã‚°ãƒ©ãƒ ã«æ±‚ã‚られるè¦ä»¶ (テストã«ã‚‚å«ã‚ãŸã„) : * å分高速ã«å‹•作ã™ã‚‹ã“ã¨ã€‚gawk ã¨åŒã˜ç¨‹åº¦ãŒç›®æ¨™ã ã£ãŸã€‚cut よりã¯é«˜é€Ÿã«ã—ãŸã‹ã£ãŸã€‚。 * cutより早ãã™ã‚‹ã®ãŒå޳ã—ã‘れã°ã€ åŒã˜ãƒ•ァイルを Unix コマンドsort ã®åŠåˆ†ç¨‹åº¦ã§ã‚ã‚‹ã“ã¨ã€‚ * $0 -p -1 ã§ãã¡ã‚“ã¨æœ€å¾Œã®åˆ—を表示ã™ã‚‹ã“ã¨ã€‚ * 列数ãŒè¡Œæ¯Žã«ç•°ãªã‚‹å…¥åŠ›ãƒ‡ãƒ¼ã‚¿ã§ã‚‚ã€ãã¡ã‚“ã¨å‹•作ã™ã‚‹ã“ã¨ã€‚ # ã“ã®ãƒ–ãƒã‚°ãƒ©ãƒ 㯠2016å¹´2月9æ—¥(ç«)ã‹ã‚‰è¡¨å½¢å¼ãƒ‡ãƒ¼ã‚¿ã«å¯¾ã™ã‚‹é“具作りã®ä¸€ç’°ã¨ã—ã¦ã€ä¸‹é‡Žå¯¿ä¹‹ãŒä½œæˆã—ãŸã‚‚ã®ã§ã‚る。 =cut