Perlでファイルをソートする方法について教えてください

このQ&Aのポイント
  • Perlを使用してファイルをソートする際に、最初の行が消えてしまう問題が発生しています。file1から1行ずつ読み込み、spanで規定した値で行を並べ替えてfile2を作成する処理を行っているのですが、なぜ最初の1行が消えてしまうのかわかりません。情報不足かもしれませんが、どのような問題が原因であるか教えていただけますか。
  • Perlでファイルをソートする際に、file2の最初の1行が消えてしまう問題が発生しています。file1から1行ずつ読み込み、spanで行を並べ替えてfile2を作成する処理を行っていますが、なぜ最初の行が消えてしまうのか理解できません。詳しい原因を教えていただけますか。
  • Perlでファイルをソートする際に問題が発生しています。file1から1行ずつ読み込み、spanで規定した値で行を並べ替えてfile2を作成する処理を行っているのですが、なぜかfile2の最初の行が消えてしまいます。どのような原因が考えられるか教えていただけますか。
回答を見る
  • ベストアンサー

ソートすると最初の1行が消えてしまいます!

いつも大変お世話になります。初心者の質問で申し訳ありません。 #!/usr/bin/perl # re-shuffle open OUT, ">file2"; open IN, "file1"; while (<IN>){ print OUT sort{&span($a) <=> &span($b)}(<IN>); } close OUT; close IN; ### sub span{ というふうに、file1から1行ずつ読み込んで、spanで規定する値で行を並べ替えてfile2を作るようにしたつもりですが、file2の最初の1行?が消えてしまいます。どこに問題があるのでしょうか、教えてください。あるいはまだ情報不足でしょうか?

  • Perl
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • zxcv0000
  • ベストアンサー率56% (111/196)
回答No.1

while (<IN>){ print OUT sort{&span($a) <=> &span($b)}(<IN>); } これが不適切で、 file1 の最初の 1行を読み捨てています。 print OUT sort{&span($a) <=> &span($b)}(<IN>); 上の 3行を、この 1行に替えましょう。(whileの行と「}」の行を削除) <IN> が、while() の条件式とブロック内の両方にあるのがまずいです。 参考までに、他にうまくいく例をいくつか。 例1========================= my @IN = <IN>; print OUT sort{&span($a) <=> &span($b)}(@IN); 例2========================= my @IN = (); while (<IN>){ push(@IN, $_); } print OUT sort{&span($a) <=> &span($b)}(@IN); ポイント1 <IN> は、スカラーとして扱うか配列として扱うかで振舞が変ります。 そこんとこをマスターしたら、一人前??? ポイント2 sort() は、入力データを全て配列に入れてから呼ぶものです。 # C の sort は、1レコードづつ呼ぶんでしたっけね? Perlの sort は違うと言うことです。

ma_san
質問者

お礼

納得しました! 早くて適切な回答、本当にありがとうございます。 コミュニティっていいですね。 今後とも何卒よろしくお願いします。

関連するQ&A

  • perlでcsvファイルから複数行を抽出したい

    プログラミング初心者です。 お知恵をお貸しください。 perlでcsvファイルから任意の複数行を、コマンドライン引数を使って抜き出したいです。 1行だけだとうまくいきますが、以下ではすべてのcsvデータが出力されてしまいます。 ----------------------getcsv.pl ここから---------------------- #!/usr/bin/perl -- use strict; use warnings; open(IN, "<adata.csv"); open (OUT, ">$bdata.csv"); while(<IN>){ if($. == $ARGV[0] || $ARGV[1] || $ARGV[2] || $ARGV[3]) { print OUT $_; } } close(IN); close (OUT); ----------------------getcsv.pl ここまで---------------------- ----------------------コマンド ここから---------------------- perl getcsv.pl 1 3 8 10 ----------------------コマンド ここまで---------------------- よろしくお願いします。

    • ベストアンサー
    • Perl
  • dで始まる行を別のファイルの末尾に書き込む

    いつもお世話になります。 「あるテキストファイルから順に行を読み込んで、 d で始まる行がマッチしたら、別のファイルの末尾の行に加えていく」、 というプログラムを書きたいのです。 下記のように書いてみたのですが、うまく動きません。どのように修正すれば動きますか? #!/usr/bin/perl open ADD, ">>jobs_done"; open IN, "jobs_tobedone"; while ($input = <IN>){ if (/^d/){ print ADD $input; } } close ADD; close IN; ぜひ知恵を貸してください。

    • ベストアンサー
    • Perl
  • ファイルの最後の行から表示させる(最新情報を5回分だけ表示)

    ファイルの最後に1行追加し、6行以上になるとファイルの先頭を1行削除。 表示は最後の行から行うスクリプトを作りたいのです。 新しい情報を5回分だけ表示する様にしたかったのですが、余りにも力技なのでもう少しスマートにやる方法を教えてもらえませんか? ----sort.txt---- 1a 2b 3c 4d ---------------- #!/usr/bin/perl $fname = "sort.txt"; print "Content-type: text/html;\n\n"; $aaa="5e"; open(OUT, ">>$fname"); flock(OUT, LOCK_EX); print OUT "$aaa\n"; flock(OUT, LOCK_NB); close(OUT); open(IN, "$fname"); $cnt = "0"; while($line = <IN>){ $a[$cnt] = "$line"; $cnt++; } close(IN); if($cnt > 5){ open(OUT, ">$fname"); flock(OUT, LOCK_EX); $cnt = "0"; while($cnt < 6){ if($cnt > 0){ print OUT "$a[$cnt]"; } $cnt++; } flock(OUT, LOCK_NB); close(OUT); } $cnt = "0"; open(OUT, "$fname"); @buff = <OUT>; close(OUT); foreach $line ( reverse @buff ){ $cnt++; print "$line<br>\n"; } exit();

    • ベストアンサー
    • Perl
  • Perlで行頭にある文字が含まれている行を全部削除して詰めたい

    perl初心者です。以下のようにデータがならんでいる時、 test111 aaaaaaaaabbbbbbbbcccccc test112 aaaaccccabbbbbbbbcccccc test113 aaaaccaaabbbbbbbbcccccc test114 acccaaaaabbbbbbbbcccccc test111 aacaaaaaabbbbbbbbcccccc test112 accaaaaaabbbbbbbbcccccc test113 aaacccaaabbbbbbbbcccccc test114 aaaaaccaabbbbbbbbcccccc test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。 途中からわかりません。 行を削除する関数が調べても見つからないのです。 #!/usr/bin/perl ; open(IN, "test.doc") or die ; open(OUT, ">testout.doc"); while(<IN>) { chomp ; if (/(\S+)/) { $name = $1 ; if ($name =~ /^test112(\S+)/) { #ここでマッチさせて、一気に行を削除して、しかも行を詰めたいのですが ; } print OUT " \n" ; } } close (IN) ; close (OUT) ; 大変困っております。宜しくお願いします。

    • ベストアンサー
    • Perl
  • 巨大ファイルの行をを逆順に並べ替えたい>perl

    下記、perlスクリプトで通常は逆順に並べ替えることができると思うのですが、ファイルの行数が1000万行程度あり、実行すると、PCのメモリを食いつぶしてしまいまともに動作しません。 どのようにすればよいでしょうか? もしくは、これに相当するようなフリーソフトはありますか? ご存知の方教えてください。 宜しくお願い致します。 #!/usr/local/bin/perl open(OUT, "1all.txt"); open (FH , ">out_all.txt"); print FH foreach( reverse <OUT> ); close(FH); close(OUT);

    • ベストアンサー
    • Perl
  • 区切りファイルの列ソートについて

    僭越ながら、質問させていただきます。 タブ記号で区切られたTSVファイルというものを扱っているのですが、まずtest.tsvファイルを配列に格納して、そこから2列目の値すべてを降順にソートし、 (列をソートした結果の行は、ちゃんと最初のまま保持され、バラけずに出力されるようにしたい) その結果をresult.txtに表示させるプログラムを作りたいと思っております。 ですが、自分が書いたプログラムではまったく動かず、どこが悪いのかも情けないことにわかりません…。  かれこれ何時間も悩んでいますが、まったく方策が見出せません。どこをどう直せばいいのか、ヒントだけでも構いませんので、教えてくださいませんでしょうか。 プログラムは以下です。 #!/usr/bin/perl use strict; use warnings; use Fatal qw/ open /; my @values; my $tsv_file = "test.tsv"; my @tsv = &readtsvfile($tsv_file); @values = sort { $a->[1] cmp $b->[1] } @tsv; open(DATAFILE, '>>result.txt') or die("error :$!"); foreach(@tsv){ print DATAFILE; } sub readtsvfile { open(IN, $_[0]); while(<IN>) { chomp; push @tsv, [ split(/\t/) ]; } close(IN); return @tsv; } close DATAFILE; このプログラムの手直しでも新しい方法でもなんでも構いません、何か教えてくだされば、本当にありがたいです。よろしくお願いします。

    • ベストアンサー
    • Perl
  • perlでCSVをソートする方法について

    perl初心者です。いつもありがとうございます。 perlでcsvファイル(1行のカラム数は200)、総行数は約3万行のファイルを37番目のカラム(-25以上25未満の数値データ)で降順ソートしその値によって行数がだいたい均等になるよう3分割し、2番目のカラムに文字でも数字でもよいのですがその4つのグループごとにフラグ(例えば1,2,3)を入れたいと思ってます。グループ化については境目の37番カラムの値は重複している場合が多いと思うのですがその場合は下(別に上でもかまいません)に入れるものとします。 ソートロジックは過去の質問を参照して理解しましたがグループ化しフラグを入れるルーチンがうまく作れません。下記のように作ったのですがこの先同じことを何度もやらなくてはならないので先に進めません。どなたかお助けください。最終的にやりたいことはカラム37でグループ化→カラム2にフラグを立てる、次にカラム2とカラム38(-25から0までの数値)でソートし同様に同じ行数になるようにグループ化→カラム3にフラグを立てる、さらにカラム2とカラム3とカラム39(-25以上25未満の数値データ)でソートし・・・同様に繰り返し最終的に1グループが100件(行)~150件(行)になるようにしたいのです。つまり約3万件のデータを3*4*2*4*2=192分割(5列の値で分類)したい、そしてどのような範囲で分割したかという情報も得たいのです。 use strict; use warnings; use utf8; use Encode; binmode STDOUT, ':encoding(utf-8)'; my $dir = './data'; # 処理するディレクトリ my $motoFile = 'customer.txt'; # もとファイル open my $fh, '<:encoding(cp932)', "$dir/$motoFile" or die 'ファイルが開けません。',"$!"; my %sorted; while (my $line = <$fh>) { my $key = (split /,/, $line)[37]; push @{$sorted{$key}}, $line; if (@{$sorted{$key}} == 1000) { open OUT, '>>:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT @{$sorted{$key}}; close OUT; @{$sorted{$key}} = (); } } open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $key (sort { $b <=> $a } keys %sorted) { if (-e "$key.tmp") { open IN, '<:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT while <IN>; close IN; } print OUT @{$sorted{$key}} if @{$sorted{$key}}; } close OUT; #↓↓↓↓ここからフラグを作成するルーチン # 行数を調べ3つに分けるルーチン my @colum37; open IN, '<:encoding(cp932)', "$dir/out.txt" or die 'ファイルが開けません。',"$!"; my @in = <IN>; close IN; my $gyousuu = scalar(@in); my $amari = $gyousuu % 3; if ($amari == 0) { my $groupGyousuu = ($gyousuu-$amari)/3; print "総行数は$gyousuu","で、1グループの行数は$groupGyousuu","ほど、余りは$amari\n"; # あまりが0の時、group1は@inの0行 ~$groupGyousuu-1行まで #         group2は@inの$groupGyousuu行 ~$groupGyousuu*2-1行まで #         group3は@inの$groupGyousuu*2行~$groupGyousuu*3-1行まで foreach my $num (1..2) { push @colum37, (split /,/, $in[$groupGyousuu*$num])[37]; # これは境目の先頭の37番目 } print "@colum37\n"; #これでここまでは完成、分けるべき値がこの配列に入っている。 open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $line (@in) { my @line = split /,/,$line; if ($line[37]>=$colum37[0]) { $line[1] = 1; }elsif ($line[37]>=$colum37[1] and $line[37]<$colum37[0]) { $line[1] = 2; }elsif ($line[37]<$colum37[1]) { $line[1] = 3; } $line = join (',',@line); print OUT $line; } close OUT; } elsif ($amari == 1) { この後未作成

    • ベストアンサー
    • Perl
  • perlで、文字列の中から何番目から何番目までの文字を抜き出したい

    perl初心者です。 文字列の中から何番目から何番目までの文字を抜き出して 別のファイルにうつす、 というスクリプトを書いています。 でも、うまくうごいてくれません。。。 恐らく、根本的におかしな部分があると思いますし、 さらに、何番目から、は指定できていても、 次の数字は文字数を意味しているのだと思いますので、 意図するものと違う気がします。 ただ、何番目から何番目 という情報だけを入力してできたら作業上大変助かります。 本当に困っております。 アドバイスをいただけると幸いです。 大変急いでおります(;;)。 宜しくお願いします!!! #!/usr/bin/perl ; open(IN, "test.txt") or die ; open(OUT, ">after_test"); while(<IN>) { chomp ; if (/(\S+)/) { \S = $S substr ($S, 12345, 12389) = { print OUT "$_\n"; } } } close (IN) ; close (OUT) ;

    • ベストアンサー
    • Perl
  • Perlでテキストファイル読み込み

    基本的な質問ですみません。 サーバ上のテキストファイルを読み込んで ローカルのテキストファイルに書き込むというだけなのですが 何度やってもできません。 以下プログラムですが #!usr/bin/perl open(IN,"http://*****/***/***.txt"); $file = <IN>; close(IN); open(OUT,"> a.txt"); print(OUT "$file"); close(OUT); サーバのアドレスは、URLうってみて見れたのでhttp://***(以下略)であってると思います。 サーバのテキストにはchmodで777と権限を与えました。 プログラムに問題あるのでしょうか。 この場合考えられる原因を教えてください。

    • ベストアンサー
    • Perl
  • ファイルの書き込み

    以下のことがしたいです。 testフォルダよりテキストファイル達を読み込み、 ある行だけ取り除いたのちnewtestフォルダに書き出したいと思います。 以下、コードになります。 #!/usr/bin/perl $n_dir = "newtest/"; $b_dir = "test/"; opendir(DIR, $b_dir); while($file = readdir(DIR)){ $nfile="$n_dir$file"; $bfile="$b_dir$file"; if (-T $bfile) { open(IN, $bfile); #testフォルダよりファイルの読み込み @list = <IN>; close(IN); open(OUT,">$nfile"); #newtestフォルダに書き出し while(@list = <IN>) { #testフォルダ内のファイルを一行ずつ読み込み if (@list =~ /test/) { #行にtestという文字列があるぎょうだけ書き出し print OUT @list; } } close(OUT); } else{next;} } closedir(DIR); ということをやりたいのですが、 書き出されるファイルは空です。 どこが間違っているのでしょうか。 エラーなどは特にありません。 testフォルダのファイル達が そのままnewtestフォルダに書き出されるのですが、 中身は空です。 ご協力お願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう