#!/usr/bin/perl 

use 5.014 ; use warnings ; # 5.001だった
use feature qw[ say ] ;
use Time::HiRes qw [ gettimeofday tv_interval ] ;
my ${ dt_start } = [ gettimeofday ] ; 
use Term::ANSIColor qw[ :constants ] ; $Term::ANSIColor::AUTORESET = 1 ; 
END{ $0 =~ s/.*\///;say STDERR DARK BOLD ITALIC YELLOW sprintf "\t--- %0.6f sec calculation ($0)." , tv_interval ${ dt_start } } ; 
use Getopt::Std ; getopts '1cC:f:i:lrs:uv=!^*:@' , \my%o ; # 5.014 で何度も実行済み
use Encode qw[ decode_utf8 encode_utf8 ] ; 
eval 'use Text::VisualWidth::UTF8 qw[ width ] ; 1 ' or die 'Installing Text::VisualWidth::UTF8 is necessary.' if $o{v} ;
use List::MoreUtils qw[ firstidx lastidx ] ;
no warnings ;
* charlen = $o{v} ? * Text::VisualWidth::UTF8::width : sub { length $_[0] }  ; 
use warnings ;
sub mainproc ; # メインの処理

$| = 1 if $o{'!'} ; # オートフラッシュの設定
my $i = do { $o{i} //= "\t" ; eval qq[qq[$o{i}]] } ;  # 区切り文字の指定処理
my $o = defined $o{f} ? do { $o{f} =~ m/^(\d*)(.*)$/ ; eval qq[qq[$2]] } : $i ; # 出力の区切り文字

mainproc ; 
exit 0 ; 

## メインの処理
sub mainproc { 

  # -l 0 で 改行文字をとる。  
  * preProcN = $o{l}//'' eq '0' ? sub { chomp } : sub { } ; # 改行文字を取るかどうか。
  # -u で utf8 とみなす。-rで chompしない。下記で2x2=4通りの処理
  * preProcU = $o{u} ? sub { $_ = decode_utf8 $_ } : sub { } ; 
  # -s str で空白に関する処理 SpaceTreatMent 
  * sptr = defined $o{s} ? $o{s} eq '0' ? sub { s/\s//gr } : sub { s/\S//gr } : sub { $_ } ; # 非破壊フラグ$_
  # -l は行全体の長さ, -cは各行中の列の本数, それが指定しないときに、それぞれのセルの文字列長さ
  * mainTreat = defined $o{l} ? sub{ & charlen ( & sptr ($_) ) } : 
                sub{ chomp ; map { & charlen($_) } map{ & sptr } split /$i/,$_,-1 } ; #  単純に各セルの文字列長さを算出。
  $o{C} .= '1' if $o{c} ;
  * colcnt = defined $o{C} ? 
                $o{C} eq '0' ? sub { @_= scalar grep { $_ eq '0' } @_  } : 
                $o{C} =~/^(0-|-0)$/ ? sub { @_ = scalar grep { $_ ne '0' } @_  } : 
                $o{C} =~ /^0be$/i ? sub { @_ = ( ( 1 + firstidx { $_ eq '0'} @_ ) , (1 + lastidx { $_ eq '0'} @_ ) )} : # end or finish
                $o{C} =~ /^0[b]$/i ? sub { @_ = 1 + firstidx { $_ eq '0'} @_ } : # end or finish
                $o{C} =~ /^0[e]$/i ? sub { @_ = 1 + lastidx { $_ eq '0'} @_ } : # start or begin
                $o{C} =~ /^-0be$/i ? sub { @_ = ( ( 1 + firstidx { $_ ne '0'} @_ ) , (1 + lastidx { $_ ne '0'} @_ ) )} : # end or finish
                $o{C} =~ /^-0[b]$/i ? sub { @_ = 1 + firstidx { $_ ne '0'} @_ } : # end or finish
                $o{C} =~ /^-0[e]$/i ? sub { @_ = 1 + lastidx { $_ ne '0'} @_ } : # start or begin
                sub { @_ = ( scalar @_ ) } : sub { } ; 
  * incOrg = $o{1} ? $o{u} ? sub { chomp ; $_ = encode_utf8 $_ ; push @_ , "|$_" } : sub { chomp ; push @_ , "|$_" } : sub {  } ; # -1 で元の入力も出す
  * incFNa  = $o{'@'} ? sub { push @_ , $ARGV } : sub { } ;  # -@ で与えられたファイル名を出す 
  # 出力を固定長にする場合の処理。
  * fmtwdt = defined $o{f} && $o{f}=~/^(\d+)/ ? 
     do { my $d = $1 ; sub { grep { $_ = sprintf "%$d".'d' , $_ ; $_ = "*" x $d if length $_ > $d }  @_ }  } : 
     sub { } ; 

  print do { my $t = <> } if $o{'='} ; # -= で先頭行をまずそのまま出力して、メインの処理対象としない。
  while ( <> ) { 
    & preProcN ; # 改行文字の処理
    & preProcU ; # UTF8に関わる処理
    #& sptr ;
    #& preProcS ; # 空白文字についての処理
    @_ = & mainTreat ; 
    & colcnt ; # 条件にあった列の数を数えるような処理 -cが指定されている場合に。
    & incFNa ; #ファイル名を末尾に付加 
    & fmtwdt ; 
    & incOrg ; # 入力した文字列を末尾に付加
    say join $o , @_ ; 
    say "^\t$ARGV" if eof && $o{'^'} ; 
    #do { $| = 1 ; print '' ; $|= 0 } if $. % $o{'*'} == 1 ; 
  } 
} ;


## ヘルプの扱い
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 ;
}


######
#
#  widths 
#    2015.02 - 2015.05 下野寿之
#    2019.10.08 大きく手を加えた。
#####

=encoding utf8 

=head1

 $0 

 入力データを各行を区切り文字ごとに区切って、文字の長さに変換して出力する。
 行末の改行文字は特にオプションで指示のない限り、長さ計算の対象ではない。

オプション :

  -i str : 区切り文字の変更。
  -l 0 :  各行の全体の長さを算出。行末文字を含めない。
  -l + :  各行の全体の長さを算出。行末文字を含めた長さとする。

  -s 0 :  空白文字を除去して処理する。i.e. 非空白文字のみが処理対象
  -s 1 :  非空白文字を除去して処理する。 i.e. 空白文字のみが処理対象。(1の部分は0以外の何でも良い)
  
  -u   :  utf-8 とみなして、長さを計算する。そうでなければ、単純なバイト長になる。
  -v   :  utf-8 の文字幅で長さを計算する(半角は1、全角は2)。(visual-width)

  -C 0 :  上記の処理で0を与える列の数を数える。(columns count)
  -C 0b :  上記の処理で0を与える列の最初の位置を与える。無ければ0。  
  -C 0e :  上記の処理で0を与える列の最後の位置を与える。無ければ0。  
  -C 0be :  上記の処理で0を与える列の最初と最後の位置を与える。無ければ0。  
  -C -0 :  上記の処理で0を与えない列の数を数える。-0でなくて0-の2文字も可。
  -C -0b :  上記の処理で0を与えない列の最初の位置を与える。無ければ0。  
  -C -0e :  上記の処理で0を与えない列の最後の位置を与える。無ければ0。  
  -C -0be :  上記の処理で0を与えない列の最初と最後の位置を与える。無ければ0。  
  -C 1 :  列の数を数える。(1の部分は実際には0または-0で無ければ何でも良い)
  -c : これは -C 1 と同じ(列の数を数える)。

  -=   :  1行目を(ヘッダと見なして)そのまま出力する。
  -1   :  各行について、元の文字列を右側に付加する。
  -@   :  ファイル名を行末に出力。(output filename)
  -^   :  ファイルを読み終わった後に、ファイル名を出力する。"^(タブ文字)ファイル名" が出力される。
  -!  : フラッシュする。バッファに貯めない。 

  -f 'Ns' : Nは数字でsは文字列。Nで固定長で数を表示し、区切り文字がsとなる。溢れた場合は*を表示
  

  --help : この $0 のヘルプメッセージを出す。  perldoc -t $0 | cat でもほぼ同じ。
  --help opt : オプションのみのヘルプを出す。opt以外でも options と先頭が1文字以上一致すれば良い。
 
ヒント: 

  $0 -= some.tsv | colsummary -= とすると、長さの分布が得られる。

開発上のメモ: 
   * セル中の空白文字を無視する様な設定を実装したい。
   * 正規表現で無視する文字列を指定できるようにしたい。
   * Unicodeの全角空白はきちんと処理をするはず。
   * 空行に対して、1列目を0文字と見なすのが妥当だと思われるが、現状、空行を返す。



=cut
