#ngmerge.pl #Yasuhiro Kondo # ver 1.2 # 20010320 # 20060921 use IO::File; $max ="\xffffff"; # 最大値(UTF-8などだとちょっとまずいかも) $delimit_tab = "\t"; $delimit_comma = ","; $delimit_colon = ":"; # ファイル名の拡張子を外す関数 sub extcut { @s = split(/\./,$_[0]); $s[0]; } # 読み込んだファイル全部から一行ずつ順に読み出した内容を配列にしたものから、一番文字列の小さいものを取り出す関数 sub min { my($min,$real_min, $test,$real_test,$hindo,$count,$out_num,$length,$out_hindo); $test = shift(@_); # 最初のファイル分から読み出して ($hindo,$real_min,$length) = split(/\t/,$test); $count = 0; $out_num = $count; $out_hindo = $hindo; foreach $test (@_) { # 次々と次のファイル分をよんで $count++; ($hindo,$real_test,$length) = split(/\t/,$test); if ($real_test lt $real_min ) { $real_min = $real_test;#最小の場合を保存しておく $out_hindo = $hindo; $out_num = $count; } } ($real_min,$out_hindo,$out_num);# 最小文字列、その頻度、ファイルの番数を返す } # ここからプログラム本体開始 # csv option 処理 if(@ARGV && $ARGV[0] eq '-c') { $opt_c = true; shift; # 要素を一つとられ、また、その分だけ数も引かれる。 } # 引数からファイルを開いて無名ハンドルの配列に押し込む foreach (@ARGV) { $fh = IO::File->new("< $_") or die "Couldn't open $_ for reading: $!\n"; push @handles, $fh; } if($opt_c) {# csvオプション最初の行にファイル名などを書く printf("文字列"); foreach (@ARGV){ printf(",%s",&extcut($_)); } printf("\n"); } #順にファイルから一行ずつ読みとって、配列lineに中味を格納する foreach $handle(@handles){ my ($s); chomp($s = <$handle>); push(@line,$s); } # 変数初期化 $count = 0; $last_number = 0; $prev_min_str = 0; # 全部読んだ最後が最終文字列でないかぎり while( $prev_min_str ne $max ){ $count++; # ファイルからの取り出しをならべたものから最小の価部分をとりだす ($min_str,$hindo,$number) = &min(@line); # 見つかったファイルの順番が$number if ($prev_min_str eq $min_str){ # 前と同じ文字列ならば続きファイルから最小値ファイルまで頻度を用意する for ($i = ($last_number + 1) ;$i <= $number ;$i++){ if ($i == $number){ if ($opt_c) { $output = $output . $hindo . $delimit_comma; } else { $output = $output . &extcut($ARGV[$i]) . $delimit_colon . $hindo . $delimit_tab; } } else { if ($opt_c) { $output = $output . "0" . $delimit_comma; } else { $output = $output . &extcut($ARGV[$i]) . $delimit_colon . "0" . $delimit_tab; } }#if $i == end }#for end $last_number = $number; } else { #prev_min ...... # 前と違う文字列なら出力。なお最後でもなく、最初でもないなら頻度を続きから最後まで用意する if (($prev_min_str ne $max) && ($count != 1)){ for ($i = ($last_number + 1) ;$i < @ARGV ;$i++){ if ($opt_c) { $output = $output . "0" . $delimit_comma; } else { $output = $output . &extcut($ARGV[$i]) . $delimit_colon ."0" . $delimit_tab; } }#if end #画面出力本体 if ($opt_c ) { chop($output);# delete last comma printf("%s\n",$output); } else { chop($output);# delete last comma printf("%s)\n",$output); }#if end }#if end prev_min .... #excel option 各出力の頭部分を作る。 if ($opt_c ) { $output = $min_str . $delimit_comma; } else { $output = $min_str . "\t("; } # 最初のファイルから最小値ファイルまで頻度を用意する for ($i = 0;$i <= $number; $i++){ if ($i == $number){ if ($opt_c) { $output = $output . $hindo . $delimit_comma; } else { $output = $output . &extcut($ARGV[$i]) . $delimit_colon . $hindo . $delimit_tab; } } else { if ($opt_c) { $output = $output . "0" . $delimit_comma; } else { $output = $output . &extcut($ARGV[$i]) . $delimit_colon . "0" . $delimit_tab; } #if end }#if $i = number .. end }#for end $last_number = $number; $prev_min_str = $min_str; }#if prev_min_str eq ..... end #最小の文字列だった分のファイルのハンドルをセット $handle = $handles[$number]; #ファイルの終わりでないかぎりそこを読んでlineの一部を取り換える if (!eof($handle)){ $line[$number] = <$handle>; chomp $line[$number]; } else { #ファイルの終わりなら、最大値を文字列の代わりにlineの一部にいれる $line[$number] = "" . "\t" . $max . "\t" . ""; }#if end } # while end ( 最終文字列が出るまで最初に戻って繰り返す) #ファイルクローズ処理 foreach $handle(@handles){ close($handle); }