#!/usr/bin/perl use 5.014 ; use warnings ; use Time::HiRes qw [ gettimeofday tv_interval ] ; my ${ dt_start } = [ gettimeofday ] ; use Encode qw[ decode_utf8 encode_utf8 ] ; use Getopt::Std ; getopts '=@:0:2:q:v:y:rL' , \my %o ; use Term::ANSIColor qw[ color :constants ] ; $Term::ANSIColor::AUTORESET = 1 ; use FindBin qw[ $Script ] ; use autodie qw [ open ] ; use List::Util qw[ max ] ; use Scalar::Util qw [ dualvar ] ; * d3 = exists $o{','} && $o{','} eq 0 ? sub{$_[0]} : sub { $_[0] =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/gr } ; my $time0 = time ; my $help = 0 ; # オンラインгѓгѓ«гѓ—гЃ®ж–‡йќўгЃ®иЎЁз¤єг‚’гЃ—гЃџгЃ‹еђ¦гЃ‹гЂ‚ my $readLines = 0 ; # иЄгЃїеЏ–гЃЈгЃџиЎЊж•° my $diffChars = 0 ; # е‡єеЉ›гЃ®иЎЊж•° my $sec = $o{'@'} // 15 ; # дЅ•з§’гЃЉгЃЌгЃ«г‚ўгѓ©гѓјгѓ г‚’з™єз”џгЃ•гЃ›г‚‹гЃ‹ $o{0} //= '-' ; # иЎЊе€—зЉ¶гЃ®е‡єеЉ›гЃ§ еЂ¤гЃЊ 0 гЃ®е ґеђ€гЃ«е‡єеЉ›гЃ™г‚‹ж–‡е— $o{q} //= "'" ; # ж–‡е—г‚’е›Іг‚Ђж–‡е— $o{y} //= 1 ; # гЃ“гЃ®ж•°г‚€г‚Ље°‘гЃЄгЃ„й »еє¦гЃ—гЃ‹гЃ©гЃ®иЎЊгЃ§г‚‚е‡єеЉ›гЃ—гЃЄгЃ‹гЃЈгЃџе ґеђ€гЃЇгЂЃе‡єеЉ›гЃ—гЃЄгЃ„гЂ‚ my $optV0 = ($o{v}//'') eq '0' ? 1 : 0 ; $SIG{INT} = sub { exit } ; $SIG{ALRM} = sub { my $n = $. =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/gr ; # 3桁ごとに区切る。 say STDERR GREEN "$n lines read ($Script). " , scalar localtime ; alarm $sec } ; alarm $sec ; if ( $o{L} ) { my %frq ; # $frq{$c}[$.] гЃ§й »еє¦г‚’й›†иЁ€ while ( <> ) { $readLines ++ ; chomp ; $frq{$_}[$.] ++ for split // , decode_utf8 $_ , 0 ; } my @chars = sort keys %frq ; binmode STDOUT, ":utf8" ; say join "\t", map { $_= '\t' if $_ eq "\t" ; "$o{q}$_$o{q}"} @chars ; for my $l ( 1 .. $. ) { say join "\t" , ( map { $frq{$_}[$l] // $o{0} } @chars ) , ":$l" } ; say join "\t", map { $_= '\t' if $_ eq "\t" ; "$o{q}$_$o{q}"} @chars ; exit ; } binmode STDOUT, ":utf8" ; my %f2 ; # $f2{ $char } [ $times ] гЃЇгЂЃеђ„ж–‡е— charг‚’дёЃеє¦timesеЂ‹жЊЃгЃ¤ж–‡е—гЃЊгЂЃдЅ•иЎЊгЃ«е‡єзЏѕгЃ—гЃџгЃ‹г‚’ж јзґЌгЂ‚ my %fs ; # $f2{$c}[$t] гЃ® ж•°$t гЃ§зЏѕг‚ЊгЃџеЂ¤г‚’иЁйЊІгЂ‚ my %fm1 ; # $fm1{$c} гЃ§ $c の出現の最大値をиЁйЊІгЂ‚dualvar である。すなわち、その時の最大値の時の、行文е—е€—г‚‚ж јзґЌгЂ‚ my %fm2 ; # %fm1 гЃЁг‚€гЃЏдјјгЃ¦гЃ„г‚‹гЃЊгЂЃжњЂеѕЊгЃ®дѕ‹г‚’еЏ–г‚Ље‡єгЃ™гЂ‚ dualvar гЃ§гЃ‚г‚‹гЃ“гЃЁгЃЇеђЊгЃгЂ‚ my ( %fm1c , %fm2c ) ; # гЃќгЃ®еЇѕеїњгЃ™г‚‹ж–‡е—е€—гЃ®е‡єзЏѕе›ћж•°г‚’ж јзґЌгЃ™г‚‹гЂ‚ my $head = <> if $o{'='} ; chomp $head if defined $head ; $SIG{INT} = sub { & output ; exit } ; & totalling () ; & output () ; exit ; # 集計 sub totalling () { while ( <> ) { $readLines ++ ; chomp ; $_ = decode_utf8 $_ ; my @F = split // , $_ , 0 ; # ж–‡е—еЌдЅЌгЃ§гЃ°г‚‰гЃ°г‚‰гЃ«гЃ™г‚‹гЂ‚0 гЃ§гЃЄгЃЏгЃ¦-1гЃ«гЃ™г‚‹гЃЁгЂЃй…Ќе€—гЃ®жњЂеѕЊгЃЊз©єж–‡е—е€—гЃ«гЃЄг‚‹гЂ‚ #say join "+" , @F ; my %f1 ; # $f1{ $char } гЃ§гЃќгЃ®иЎЊгЃ«гЃќгЃ®ж–‡е—гЃЊдЅ•е›ће‡єзЏѕгЃ—гЃџгЃ‹г‚’ж јзґЌгЂ‚ if ( ! $o{r} ) { $f1 { $_ } ++ for @F } # еЌзґ”に集計 else { my %t ; # $t{$c}гЃЇ $cгЃЊйЂЈз¶љгЃ§жњЂй•·дЅ•ж–‡е—з¶љгЃ„гЃџгЃ‹г‚’ж јзґЌгЃ™г‚‹г‚€гЃ†гЃ«гЃ™г‚‹гЂ‚ my $z = '' ; # з›ґе‰ЌгЃ®ж–‡е— my $d = 1 ; # й•·гЃ• push @F , '' ; # и»ЅгЃ„гѓ€гѓЄгѓѓг‚Ї for ( @F ) { if ( $_ eq $z ) { $d ++ ; #print $d ; } else { $t {$z} = $d ; #print $d if $d > 1 ; $d = 1 ; # гѓЄг‚»гѓѓгѓ€ $f1 { $z } = $t{ $z } if ( $f1 { $z } // 0 ) < $t { $z } ; } $z = $_ ; } delete $f1{''} ; } $f2 { $_ } [ $f1{$_} ] ++ for keys %f1 ; $fs { $_ } = 1 for values %f1 ; for my $c ( keys %f1 ) { do{ $fm1c{$c} = 0 ; $fm1{$c} = dualvar $f1{$c},$_ } if ($fm1{$c}//0) < $f1 { $c } ; $fm1c { $c } ++ if $_ eq $fm1{$c} ; # dualvar гЃ®ж–‡е—е€—гЃ®ж–№гЃ®жЇ”ијѓгЃ«гЃЄгЃЈгЃ¦гЃ„г‚‹ do{ $fm2c{$c} = 0 if defined $fm2{$c} && $fm2{$c} ne $_ ; $fm2{$c} = dualvar $f1{$c},$_ } if ($fm2{$c}//0) <= $f1 { $c } && $fm1{$c} ne $_ ; $fm2c { $c } ++ if defined $fm2{$c} && $_ eq $fm2{$c} ; # dualvar гЃ®ж–‡е—е€—гЃ®ж–№гЃ®жЇ”ијѓгЃ«гЃЄгЃЈгЃ¦гЃ„г‚‹ } } } # е‡єеЉ› sub output () { #say STDERR $o{y} ; exit ; my @fsE = sort { $a <=> $b } keys %fs ; # E гЃЇ Entire гЃ®й ж–‡е—のつもり。数値の集合となる。 my @chars = grep { scalar @{$f2{$_}} > $o{y} } sort keys %f2 ; $diffChars = @chars ; say UNDERLINE join "\t" , 'char', @fsE , $optV0 ? () : 'examples' . FAINT '(count)' ; for my $c ( @chars ) { print "$o{q}$c$o{q}\t" ; my @out ; push @out , map { $f2{$c}[$_] || $o{0} } @fsE ; my $fm1c = "$o{q}$fm1{$c}$o{q}" . FAINT "($fm1c{$c})" if defined $fm1{$c} ; # my $fm2c = "$o{q}$fm2{$c}$o{q}" . FAINT "(>= $fm2c{$c})" if defined $fm2{$c} ; # 直前の行とよく似ている。保守時にトラブりがち。 #push @out , map {"$o{q}$_$o{q}"} grep { defined $_ } $fm1{$c}, $fm2{$c} unless $optV0 ; push @out , grep { defined $_ } $fm1c, $fm2c unless $optV0 ; do { splice @out , -1 , 1 ; push @out , FAINT "--"} if $out[-1] eq $out[-2] && @fsE +2 == @out; # еђЊгЃгЃЄг‚‰й™¤еЋ»гЂ‚ # гѓ€гѓЄгѓѓг‚гѓј say join "\t" , @out ; } } END { exit if $help ; my $procsec = sprintf "%.5f", tv_interval ${ dt_start } ; #time - $time0 ; # гЃ“гЃ®гѓ—гѓг‚°гѓ©гѓ の処理にかかった秒数。比較する2еЂ‹гЃ®ж™‚е€»гЃЇз§’еЌдЅЌгЃЄгЃ®гЃ§гЂЃВ±1з§’жњЄжєЂгЃ®иЄ¤е·®гЃЇз™єз”џгЃ™г‚‹гЂ‚ $readLines //= $. ; # Ctrl+Cの連打で必要となる処理。 return if ($o{2}//'') eq 0 ; my $linenumeral = $readLines > 1 ? 'lines' : 'line' ; print STDERR BOLD FAINT ITALIC & d3 ( $readLines ) . " $linenumeral read" ; print STDERR BOLD FAINT ITALIC $o{'='} ? " after $o{q}$head$o{q}. " : ". " ; my $charnumeral = $diffChars > 1 ? 'characters' : 'character' ; print STDERR BOLD FAINT ITALIC & d3 ( $diffChars ) . " different $charnumeral in input are shown. " ; my $s = tv_interval $dt_start , [ gettimeofday ] ; say STDERR BOLD FAINT ITALIC " -- $Script ; " . $procsec . " sec. in process" ; } ## гѓгѓ«гѓ—の扱い sub VERSION_MESSAGE {} sub HELP_MESSAGE { use FindBin qw[ $Script ] ; $help = 1 ; $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 г‚ігѓћгѓігѓ‰ $0 inputfile $0 < inuptfile cat inputfile | $0 еђ„ж–‡е—yгЃЊдёЃеє¦xеЂ‹жЊЃгЃ¤ж–‡е—гЃЊгЂЃдЅ•еЂ‹гЃ®иЎЊгЃ«е‡єзЏѕгЃ—гЃџгЃ‹г‚’иЎЊе€—зЉ¶гЃ«иЎЁз¤єгЃ™г‚‹г‚ігѓћгѓігѓ‰гЃ§гЃ‚г‚‹гЂ‚ дё‹иЁгЃ®з”ЁйЂ”гЃ«дЅїгЃ€г‚‹гЂ‚д»–гЃ«г‚‚е№…еєѓгЃ„з”ЁйЂ”гЃ«дЅїгЃ€г‚‹гЃ§гЃ‚г‚ЌгЃ†гЂ‚ - е°Џж•°з‚№гЃЊ2回出現したとか、括弧の対応がついていない可能性が検出容ж“гЂ‚ - 特別値や特殊文е—も見つけやすくなる。 г‚Єгѓ—г‚·гѓ§гѓігЃ«й–ўгЃ—гЃ¦: -0 STR : й »еє¦гЃЊ0гЃ§гЃ‚г‚‹гЃ“гЃЁг‚’STRで表示。未指定なら"-" гЃЁгЃЄг‚‹гЂ‚-0 0 гЃ®г‚€гЃ†гЃЄдЅїгЃ„ж–№гЃЊжѓіе®љгЃ•г‚Њг‚‹гЂ‚ -2 0 : 入力行数や処理時間などの2ж¬Ўжѓ…е ±г‚’гЂЃжЁ™жє–г‚Ёгѓ©гѓје‡єеЉ›гЃ«е‡єеЉ›гЃ—гЃЄгЃ„гЂ‚ -q STR : е‡єзЏѕгЃ—гЃџеђ„ж–‡е—г‚’гЂЃSTR で囲って表示する。未指定ならシングルクォーテーション(')гЂ‚'1'гЃ®г‚€гЃ†гЃ«гЃЄг‚‹гЂ‚ -r : з•°гЃЄг‚‹еђ„ж–‡е—гЃЊгЂЃгЃќг‚ЊгЃћг‚ЊгЃ®иЎЊгЃ§гЂЃжњЂй•·гЃ§дЅ•ж–‡е—йЂЈз¶љгЃ—гЃџгЃ‹г‚’гЂЃж•°гЃ€г‚‹г‚€гЃ†гЃ«гЃ™г‚‹гЂ‚(experimental) -v 0 : е…·дЅ“дѕ‹гЃ®жЉ‘е€¶гЂ‚(е‡єеЉ›гЃ•г‚Њг‚‹е…·дЅ“дѕ‹гЃЇгЂЃгЃќгЃ®ж–‡е—г‚’жњЂг‚‚е¤љгЃЏжЊЃгЃ¤е…ҐеЉ›иЎЊгЃ§гЂЃжњЂе€ќгЃ®г‚‚гЃ®гЃЁгЂЃгЃќг‚ЊгЃЁгЃЇз•°гЃЄг‚‹жњЂеѕЊгЃ®г‚‚гЃ®гЃ§гЃ‚г‚‹гЂ‚) -y N : жЁЄи»ёгЃ®еЂ¤гЃЊ N д»ҐдёЉгЃ®е ґеђ€гЃ®гЂЃж–‡е—гЃ®гЃїе‡єеЉ›гЃ™г‚‹гЂ‚(experimental) -L : еђ„иЎЊгЃ«гЃ©г‚“гЃЄж–‡е—гЃЊе‡єзЏѕгЃ—гЃџгЃ‹г‚’гЂЃиЎЁгЃ«гЃѕгЃЁг‚Ѓг‚‹гЂ‚-LгЃЄгЃ—гЃ®е ґеђ€гЃ«жЇ”гЃ№гЃ¦гЂЃзё¦жЁЄгЃЊеЏЌи»ўгЃ—гЃ¦гЃ„г‚‹гЃ“гЃЁгЃ«жіЁж„ЏгЂ‚ seq 12 | $0 -L -@ N : Nз§’гЃЉгЃЌгЃ«гЂЃе…ҐеЉ›гЃ®иЄгЃїеЏ–г‚ЉзЉ¶жіЃг‚’жЁ™жє–г‚Ёгѓ©гѓје‡єеЉ›гЃ«е‡єеЉ›гЃ™г‚‹гЂ‚ --help : このオンラインгѓгѓ«гѓ—гЃ®ж–‡йќўг‚’иЎЁз¤єгЃ™г‚‹гЂ‚ гЃќгЃ®д»–: * е…·дЅ“дѕ‹гЃ®иЎЁз¤єгЃ®иЄ¬жЋгЃЇгЂЃг‚‚гЃ†е°‘гЃ—жЈзўєгЃ§зљ„зўєгЃ§з°ЎжЅ”гЃЄиЄ¬жЋгЃЊеї…и¦ЃгЂ‚(е†…йѓЁгЃ®гѓ—гѓг‚°гѓ©гѓ を見る必要あり。) * -: гЃ«г‚€гЃЈгЃ¦гЂЃе…·дЅ“дѕ‹гЃ®гЃЁгЃ“г‚ЌгЃ«иЎЊз•ЄеЏ·гЃЊд»еЉ гЃ•г‚Њг‚‹г‚€гЃ†гЃ«гЃ—гЃџгЃ„гЂ‚ 123:"someline" гЃ®г‚€гЃ†гЃ«гЂ‚ * е‡єеЉ›гЃ®иЎЁз¤єй †еєЏгЃ«гЃ¤гЃ„гЃ¦гЂЃtimes (й »еє¦; жЁЄи»ёгЃ®ж•°) гЃЊе¤љгЃ„й †гЃ«иЎЁз¤єгЃ™г‚‹г‚Єгѓ—г‚·гѓ§гѓігЃЊж¬ІгЃ—гЃ„гЂ‚ * д»–гЃ®иЎЁз¤єй †еєЏгЃ®г‚Єгѓ—г‚·гѓ§гѓіг‚‚иЂѓгЃ€гЃџгЃ„гЂ‚еђ„ж–‡е—гЃ®е‡єзЏѕй »еє¦й †гЃЄгЃ©гЂ‚-~гЃ§йЂ†и»ўгЃ•гЃ›г‚‹гЃЄгЃ©гЂ‚ * е…·дЅ“дѕ‹гЃ«гЃЉгЃ„гЃ¦гЂЃгЃќгЃ®ж–‡е—е€—гЃЊдЅ•е›ће‡єзЏѕгЃ—гЃџгЃ‹г‚’жљ—гЃ„ж–‡е—で括弧内で表示させたい。 * ж–‡е—コードも出したいが、他のコマンドで今は代替できるので、もしかしたら後で実装する。 * 1ж–‡е—еЌдЅЌгЃ«гЃ°г‚‰гЃ°гЃ«гЃ—て処理するので、このコマンドは動作が少し遅く感гЃг‚‰г‚Њг‚‹гЃ‹г‚‚гЂ‚ =cut