#!/usr/bin/perl -T # csv2tsv # Toshiyuki Shimono at Uhuru Corporation in Tokyo. # 2015-09-28 , 2016-07-06, 2018-06-08 use 5.014 ; use strict ; use warnings ; # Confirmed also for 5.010 use Getopt::Std ; getopts '!~2n:t:', \my %o ; use Text::CSV_XS ; # Not a core module. use FindBin qw [ $Script ] ; use Term::ANSIColor qw[ :constants color ] ; $Term::ANSIColor::AUTORESET = 1 ; my $tE = ! defined $o{t} ? "\t" : $o{t} ; # eval qq[qq[$o{t}]] # レコード(セル)ã«ç¾ã‚ŒãŸã‚¿ãƒ–æ–‡å—ã‚’ä½•ã®æ–‡å—列ã«ç½®ãæ›ãˆã‚‹ã‹ my $nE = ! defined $o{n} ? "\n" : $o{n} ; # eval qq[qq[$o{n}]] # レコード(セル)ã«ç¾ã‚ŒãŸæ”¹è¡Œæ–‡å—ã‚’ä½•ã®æ–‡å—列ã«ç½®ãæ›ãˆã‚‹ã‹ my $tnChange = defined $o{t} || defined $o{n} ; my ( $tC , $tF, $tL ) = (0,0,0) ; # タブ文å—ã®ã€å€‹æ•°ã€ãƒ•ィールド数ã€è¡Œæ•° my ( $nC , $nF, $nL ) = (0,0,0) ; # 改行文å—ã®æ•° <-- - "\n" ä»¥å¤–ã®æ”¹è¡Œæ–‡å—ã®å¯¾ç–ã¯ã©ã†ã™ã‚‹? perlport をよãèªã‚‚ㆠ& rev if $o{'~'} ; & main ; exit 0 ; sub rev ( ) { while (<>){ chomp ; s/\r$// ; my @F = split /\t/, $_ , -1 ; print join ',' , map {qq["$_"]} @F ; print "\n" ; } exit 0; } sub main ( ) { binmode *STDOUT , ":utf8" ; print STDERR RED "Waiting CSV-formatted input from STDIN.. ($Script) \n" if -t ; eval { reading ( ) } ; #END { warn $@ if $@ } ; # <-- CSVå½¢å¼ã‹ã‚‰å°‘ã—é•ã†ã¨ã€END{}ã¯å®Ÿè¡Œã‚’ç¶šã‘ã‚‹ã“ã¨ã¯ã§ãã‚‹ãŒã€ã“ã®è¡Œã¯å®Ÿè¡Œã—ãªã„よã†ã 。ã“ã®è¡Œã¯ä½•ã®å½¹ã«ç«‹ã¤ã®ã‹? } sub reading ( ) { my $lines = 1 ; # CSV ã§èªã¿è¾¼ã‚“ã§ã„ã‚‹ã®ã§ã€$. ã¯2以上増ãˆã‚‹ã“ã¨ãŒã‚る。èªã¿å–る度ã«ã€ $lines ã‹ã‚‰ $. 行目ã¾ã§ã¨èªè˜ã™ã‚‹ãŸã‚。 our $csv = Text::CSV_XS -> new ( { binary => 1 } ); while ( my $x = $csv -> getline( *ARGV ) ) { # *ARGVã¯Old(er) support 㨠perldoc Text::CSV_XSã«è¨˜è¼‰ã‚り。将æ¥ã‚µãƒãƒ¼ãƒˆã•れãªã„ã‹ã‚‚。 my @F = @$x ; # 入力レコードä¸ã«ã‚¿ãƒ–æ–‡å—ã‹æ”¹è¡Œæ–‡å—ãŒç¾ã‚ŒãŸå ´åˆã«ã€ã‚«ã‚¦ãƒ³ãƒˆã—ã€è¡¨ç¤ºã™ã‚‹ã€‚ if ( ! $o{'!'} ) { my ( $cn, $ct ) ; # ãã®è¡Œã§ã®ã€æ”¹è¡Œæ–‡å—ã®å€‹æ•°ã¨ã‚¿ãƒ–æ–‡å—ã®ç™ºç”Ÿã—ãŸãƒ•ィールドã®å€‹æ•° print STDERR BRIGHT_RED qq[Warning: "\\n" detected at input btw. $lines - $. -th line ($Script)\n] if $cn = grep { m/\n/ } @F and ++ $nL and $nF += $cn ; print STDERR BRIGHT_RED qq[Warning: "\\t" detected at input btw. $lines - $. -th line ($Script)\n] if $ct = grep { m/\t/ } @F and ++ $tL and $tF += $ct ; } # タブ文å—ã¨æ”¹è¡Œæ–‡å—ã‚’ç½®æ›ã™ã‚‹ã€‚(改行文å—ã‚’ä»»æ„ã®æŒ‡å®šæ–‡å—ã€ã‚¿ãƒ–æ–‡å—ã‚’ä»»æ„ã®æŒ‡å®šæ–‡å—ã«å¤‰æ›ã™ã‚‹ã ã‘ã ãŒã€ã‚„ã‚„ã“ã—ã„アルゴリズムを採用ã›ã–ã‚‹ã‚’å¾—ãš) if ( $tnChange ) { for ( @F ) { my @tmp = split /([\t\n])/ , $_ , -1 ; #print CYAN join "-", @tmp ; $_ = join '' , map { $_ eq "\t" ? do{ $tC++ ; $tE } : $_ eq "\n" ? do{ $nC++ ;$nE }: $_ } @tmp ; } } # å‡ºåŠ›å‡¦ç† print join ("\t", @F) . "\n" ; print "\n" if $o{2} ; # # 出力å„行ã®é–“ã«ç©ºè¡Œã‚’挿入ã™ã‚‹å ´åˆã®å‡¦ç† $lines = $. + 1 ; # <- tricky! } $csv->eof; # <-- - å¿…è¦ã‹? return if $o{'!'} ; print STDERR GREEN qq[Totally "\\n" appeared in $nF record(s) in $nL line(s) for output.] if $nL ; print STDERR GREEN qq[ $nC count(s) of "\\n" in input.] if $nC ; print STDERR "\n" if $nL || $nC ; print STDERR GREEN qq[Totally "\\t" appeared in $tF record(s) in $tL line(s) for output.] if $tL ; print STDERR GREEN qq[ $tC count(s) of "\\t" in input.] if $tC ; print STDERR "\n" if $tL || $tC ; END{ exit if $o{'~'} ; my @tmp = $csv -> error_diag () ; # ($cde, $str, $pos, $rec, $fld) = $csv->error_diag (); if ( $tmp[0] != 2012 ) { # perldoc Text::CSV_XS ã§ 2012 をå‚照。EOFã‚’æ„味ã™ã‚‹ã€‚ print STDERR BRIGHT_RED join (":",@tmp),"\n" ; exit 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 ; } =encoding utf8 =head1 $0 file.csv > file.tsv $0 < file.csv > file.tsv CSV å½¢å¼(RFC 4180)ã®ãƒ•ァイルを TSVå½¢å¼(タブ文å—区切り) ã«å¤‰æ›ã™ã‚‹ã€‚ 出力ã«ã¤ã„ã¦ã¯ã€æ–‡å—コード UTF-8 ã§æ”¹è¡Œã‚³ãƒ¼ãƒ‰ã¯ "\n" ã¨ãªã‚‹ã€‚ オプション: -t str : 入力ã«ã‚¿ãƒ–æ–‡å—ãŒã‚れã°ã€ãれを何ã«ç½®ãæ›ãˆã‚‹ã‹ã‚’æ–‡å—列表ç¾ã§æŒ‡å®šã™ã‚‹ã€‚ -n str : å…¥åŠ›ã«æ”¹è¡Œæ–‡å—ãŒã‚れã°ã€ãれを何ã«ç½®ãæ›ãˆã‚‹ã‹ã‚’æ–‡å—列表ç¾ã§æŒ‡å®šã™ã‚‹ã€‚ -! : 入力ã®ãƒ¬ã‚³ãƒ¼ãƒ‰å†…ã«ã€ã‚¿ãƒ–æ–‡å—ã¾ãŸã¯æ”¹è¡Œæ–‡å—ãŒã‚ã£ã¦ã‚‚ã€è¦å‘Šã‚’出ã•ãªã„。付ã‘ã‚‹ã“ã¨ã§é«˜é€ŸåŒ–ã¯ã™ã‚‹ã€‚(no check) -2 : レコードã®åŒºåˆ‡ã‚Šã‚’å˜ä¸€ã® \n ã§ã¯ãªãã¦ã€2個続ã‘㟠\n\n ã«ã™ã‚‹ã€‚CSVã®ã‚»ãƒ«å†…ã«æ”¹è¡Œæ–‡å—ãŒã‚ã‚‹å ´åˆã«ä½¿ã†ã‹ã‚‚ã—れãªã„。 -~ : TSVå½¢å¼ã‹ã‚‰CSVå½¢å¼ã«å¤‰æ›ã€‚å„レコードをダブルクォーテーションã§å›²ã¿ã€ã‚³ãƒ³ãƒžã§åŒºåˆ‡ã‚‹ã€‚ --help : ã“ã® $0 ã®ãƒ˜ãƒ«ãƒ—メッセージを出ã™ã€‚ perldoc -t $0 | cat ã§ã‚‚ã»ã¼åŒã˜ã€‚ --help opt : オプションã®ã¿ã®ãƒ˜ãƒ«ãƒ—を出ã™ã€‚opt以外ã§ã‚‚ options ã¨å…ˆé ãŒ1æ–‡å—以上一致ã™ã‚Œã°è‰¯ã„。 =cut