perlでCSVをソートする方法について

このQ&Aのポイント
  • perlでcsvファイルを37番目のカラムで降順ソートし、値によって行数が均等になるように3分割し、グループごとにフラグを入れたいです。
  • ソートロジックは理解しましたが、グループ化しフラグを入れるルーチンがうまく作れません。
  • 最終的には3万件のデータを分割し、5列の値で分類して、グループごとにフラグを入れたいです。
回答を見る
  • ベストアンサー

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
  • 回答数4
  • ありがとう数3

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

  • ベストアンサー
  • N60-BASIC
  • ベストアンサー率80% (17/21)
回答No.3

## 面白そうだったので、自分流に書いてみました。 ## 適当に書いたので、バグがあったらごめんなさいです。 ## ← ##で始まる行は解説用コメントです use strict; use warnings; use utf8; binmode(STDOUT, ':utf8'); binmode(STDERR, ':utf8'); ## エラー出力も考慮しましょう my $dir = './data'; # 処理するディレクトリ my $motoFile = 'customer.txt'; # もとファイル # データファイル読み込み my @array; open(my $fh, '<:encoding(cp932)', "$dir/$motoFile") or die 'ファイルが開けません。',"$!"; while(my $line = <$fh>) { chomp $line; ## 「配列リファレンスの配列」を作る。複数カラムでのソートが楽になります push(@array, [ split(/,/, $line) ]); } close($fh); # 配列リファレンス内の指定カラム値を比較して配列をソート ## どこを使ってソートするかわからなかったので ## とりあえず[37]~[41]でソート my @sorted = sort { $b->[37] <=> $a->[37] || $b->[38] <=> $a->[38] || $b->[39] <=> $a->[39] || $b->[40] <=> $a->[40] || $b->[41] <=> $a->[41] } @array; # ソート済みデータファイル出力 ## 分類用フラグは後付けで計算 open(my $fh_out, '>:encoding(cp932)', "$dir/out.txt") or die "Can't open: $!"; for(my $i=0; $i<192; $i++) { # 192等分したブロックの先頭と終了のインデックスを求める ## 余りの分を先頭に近いブロックに寄せる方法については宿題としておきます(難しくないです) my $start = int(@sorted * $i / 192); my $end = int(@sorted * ($i+1) / 192) - 1; # 分類用フラグの計算 my @flag_value = ( int($i / (4 * 2 * 4 * 2)) % 3 + 1, int($i / (2 * 4 * 2)) % 4 + 1, int($i / (4 * 2)) % 2 + 1, int($i / 2) % 4 + 1, $i % 2 + 1, ); # 出力範囲の表示 ## とりあえず標準出力に。 ## データ形式に合わせて見やすいように整形するといいでしょう printf( "[%d, %d, %d, %d, %d] (%s, %s, %s, %s, %s) ~ (%s, %s, %s, %s, %s)\n", @flag_value, @{$sorted[$start]}[37..41], @{$sorted[$end]}[37..41], ); # ブロック毎にフラグを上書きしながら出力 for(my $j=$start; $j<=$end; $j++) { ## 分類用フラグをどこに立てるかわからなかったので ## とりあえず[2]~[6]に立てる @{$sorted[$j]}[2..6] = @flag_value; # 出力 print $fh_out join(',', @{$sorted[$j]}),"\n"; } } close($fh_out); ## 具体的な用途が不明なので以下は独り言ですが、 ## 正直なところ、カラム内にインデックスフラグ立てるメリットは ## ほとんどない気がします・・。 ## 結果を別ファイルに分けるならわかるのですが、それならなおさら ## カラム内にフラグを持たせる必要はないように思えます。

datamunging
質問者

お礼

すごいです。動きました。ありがとうございます。私には読むのも時間がかかります。こんなに短い時間で書けるとは!ただ、ただ驚きです。私には読むだけでも2日~3日かかりますのでとりあえずお礼させていただきます。

datamunging
質問者

補足

動作結果です。 $ ./mainBunkatu3.pl Malformed UTF-8 character (unexpected continuation byte 0x81, with no preceding start byte) at ./mainBunkatu3.pl line 64. [1, 1, 1, 1, 1] (18.90, 0.00, 0.00, 0.00, 0.00) ` (8.70, 0.00, 0.00, 0.00, 0.00) [1, 1, 1, 1, 2] (8.70, 0.00, 0.00, 0.00, 0.00) ` (7.40, 0.00, 0.00, 0.00, 0.00) ~中略~ [1, 4, 2, 4, 1] (-0.50, 0.00, 0.00, 0.00, 0.00) ` (-0.59, 0.00, 0.00, 0.00, 0.00) [1, 4, 2, 4, 2] (-0.59, 0.00, 0.00, 0.00, 0.00) ` (-0.59, 1.00, 1.00, 0.00, 1.00) [2, 1, 1, 1, 1] (-0.59, 0.00, 0.00, 0.00, 1.00) ` (-0.69, 3.00, 4.00, 1.00, 3.00) [2, 1, 1, 1, 2] (-0.69, 1.00, 0.00, 0.00, 1.00) ` (-0.70, 0.00, 0.00, 0.00, 0.00) ~中略~ [2, 4, 2, 4, 1] (-3.90, 0.00, 1.00, 0.00, 2.00) ` (-4.00, 0.00, 0.00, 0.00, 0.00) [2, 4, 2, 4, 2] (-4.00, 1.00, 1.00, 0.00, 0.00) ` (-4.00, 0.00, 0.00, 0.00, 0.00) [3, 1, 1, 1, 1] (-4.00, 0.00, 0.00, 0.00, 0.00) ` (-4.10, 0.00, 0.00, 0.00, 1.00) [3, 1, 1, 1, 2] (-4.10, 0.00, 0.00, 0.00, 0.00) ` (-4.20, 0.00, 0.00, 0.00, 0.00) ~中略~ [3, 4, 2, 3, 2] (-11.70, 0.00, 0.00, 0.00, 0.00) ` (-12.30, 0.00, 0.00, 0.00, 0.00) [3, 4, 2, 4, 1] (-12.30, 0.00, 0.00, 0.00, 0.00) ` (-13.70, 0.00, 0.00, 0.00, 0.00) [3, 4, 2, 4, 2] (-13.70, 4.00, 3.00, 0.00, 0.00) ` (-22.50, 0.00, 1.00, 0.00, 0.00) 実は境目の-0.59(一つめのフラグ)はどちらかに入れたいのです。同様に-4の人たちもです。

その他の回答 (3)

回答No.4

各段階で等分するのなら、分割しながらソートしてもソートしてから分割しても 同じ事なので、本当は値の範囲ごとに区分したいんだと思いますが。 Unix系ならシェルスクリプトで手軽にできますよ。 #!/bin/sh line=$(( $(sed -n '$=' customer.txt) / (3 * 4 * 2 * 4 * 2) + 1 )) sort -s -t, -k38nr -k39nr -k40nr -k41nr -k42nr | split -a 3 -d -l ${line} mkdir -p ./dir mv x[0-9][0-9][0-9] ./dir

datamunging
質問者

お礼

大変ありがとうございます。私には想像もつかない方法をご存じで、世の中にはすごい人がいるものだなぁとただただ感じいっております。 試してみます。これも解読するのには3日以上かかるかと思われますのでお礼を先にさせていただきます。

datamunging
質問者

補足

皆さん、なかなかやりたいことが伝えられず申し訳ありません。下のANo.3の方にはもっと補足を書こうと思ったのですが間違えてクリックし確定してしまいました。

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.2

前回の回答で $count をクリアする文を入れるのを忘れていました。すみませんが、修正願います。 if ($count == $groupGyousuu + ($idx_amari < $amari ? 1 : 0)) { close OUT; $flag = next_flag($flag); $idx_amari++; $count = 0; # この文を追加 open OUT '>:encoding(cp932)', "$dir/out$flag.txt" or die "Can't open: $!"; }

datamunging
質問者

お礼

ありがとうございます。大変参考になります。お礼が遅くなり申し訳ありません。試したり読んだりしているのですが初心者の私にはとても敷居が高くて、まだまだ時間がかかってしまいそうなのでお礼させていただきます。

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.1

out.txt を作成するまでは、よくできているいるように思います。その後の細分化しながらのグループ分けは、あまり有効的なやり方ではありません。カラム37番目 (コード中も 37 になっているので、0 から数えた?) が整数であるとすると、最大 50 種類で平均しても1種類で 600 行にもなってしまうからです。ソート対象は37番目のカラムのみのようですので、ソート済みの out.txt の行を順に 11111, 11112, 11121, ..., 34232, 34241, 34242 に割り当てたほうが簡単に済むように思います。 while (my $line = <$fh>) { ... if (eof) { $groupGyousuu = int($. / 192); $amari = $. % 192; } } 最初の while ループの最終行でグループ行数と余りの行を算出しておきます。次のコードでは、フラグをファイ名に含めてあります。行に入れる場合は、コメントアウトしてある行を参考にしてみてください。(なお、余りの行がない場合、余分な空ファイルが作られてしまいますが、繁雑になるので除外のコードを入れてありません。) my ($count, $idx_amari, $flag) = (0, 0, '11111'); open IN, '<:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; open OUT, '>:encoding(cp932)', "$dir/out$flag.txt" or die "Can't open: $!"; while (my $line = <IN>) { # substr($line, index($line, ','), 0) = ',' . join(',', split //, $flag); print OUT $line; $count++; if ($count == $groupGyousuu + ($idx_amari < $amari ? 1 : 0)) { close OUT; $flag = next_flag($flag); $idx_amari++; open OUT '>:encoding(cp932)', "$dir/out$flag.txt" or die "Can't open: $!"; } } close OUT; sub next_flag { my @temp = split //, $_[0]; my @limit = (3, 4, 2, 4, 2); foreach my $i (reverse 0 .. 4) { if ($temp[$i] < $limit[$i]) { $temp[$i]++; return join('', @temp); } else { $temp[$i] = 1; } } }

関連するQ&A

  • CSVデータ「","」と「,」混在読取り出来ず

    ソート機能がうまく動作しなくなりました。 CSVが以下のようなものとなったときにソートがうまく動作しなくなってしまいました。 CSVデータの区切りが「","」と「,」の混在で区切られてます。 (ここから) データa "山田","埼玉県","男性" "田中","埼玉県","男性" "井上","栃木県","女性" "志村","千葉県","男性" (ここまで) だったり (ここから) データb 1,山田,埼玉県,男性,50,"予算2,000円",0 2,田中,埼玉県,男性,36,予算なし,0 3,井上,栃木県,女性,30,予算100円,0 4,志村,千葉県,男性,27,"予算300,000円",0 (ここまで) このようなテータの時もあります。 以前のアドバイスをもとに以下のように作成いたしました。 (ここから) while (my $line = <$ifh>) { if ($socnt == 0 ){$socnt++;next;} my $key = (split /\",\"/, $line)[$ccsv]; push @{$sorted{$key}}, $line; if (@{$sorted{$key}} == 1000) { open OUT, ">>./$key.tmp" or die "Can't open: $!"; print OUT @{$sorted{$key}}; close OUT; @{$sorted{$key}} = (); } } (ここまで) この場合だと my $key = (split /\",\"/, $line)[$ccsv]; データaはうまくいくのですが、データbがうまくソートが動作いたしません。 my $key = (split /,/, $line)[$ccsv]; ではデータbはうまくいくのですが、データaうまくソートが動作いたしません。 条件式で混在認識方法があるかと思っている(ないかもしれませんが、わたしには分かりません)ので質問いたしました。 ご教授いただけますと幸いです。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • プログラムの高速化

    いつもお世話になっております.以下のプログラムをできるだけ高速化したいと思います. use warnings; use strict; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); open(FILE, $dir) or die "$dir: $!"; while (my $line = <FILE>) { my ($a,$b,$c,$d,$e,$f) = split( /,/ , $line ); my $name = $a.",".$b; open(NEWFILE, ">> ./out/$name.txt") or die "$dir: $!"; print NEWFILE $line; close(NEWFILE); } } close(FILE); closedir(DIR); やっていることは,ディレクトリ内のテキストファイルを読み込んでいって,splitでカンマ区切りにした,$a,$bをファイル名として下のディレクトリのoutに保存していくというものです. ファイル数が数千あり,各ファイルも数千行となるため,このソースを高速化する方法はありますでしょうか.ご回答よろしくお願いします.

    • ベストアンサー
    • Perl
  • 一つのテキストファイルと複数のファイルの結合

    よろしくお願いします.ディレクトリ内の一つのテキストファイル(joint.txt)と複数のファイルの結合を行ごとに隣へ結合するプログラムを作成しています.ここで以下のプログラムを作成したのですが,うまくいかないため,誤っている部分をご指摘願えないでしょうか. my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); open(FILE, $dir) or die "$dir: $!"; open(FILE2,"joint.txt"); my @file = <FILE>; my @file2 = <FILE2>; close(FILE); close(FILE2); foreach my $line (@file) { foreach my $line2 (@file2) { chomp $line2; $line = "$line2.",".$line"; } } open(NEWFILE, "> $dir") or die "$dir: $!"; print NEWFILE @file; print NEWFILE @file2; close(NEWFILE); } closedir(DIR);

    • ベストアンサー
    • Perl
  • [perl5.8] SJISで出力したはずのファイルにutf8フラグが

    1)SJISで以下の2行を含むファイルを作成し、   sjis.txtという名前で保存します。 "ホツカイドウ" "北海道" 2)SJISで以下のスクリプトを作成します。 #=== one.pl === use encoding 'Shift_JIS'; use open IN => ":encoding(Shift_JIS)"; use open OUT => ":encoding(Shift_JIS)"; my $infile = 'sjis.txt'; my $outfile = 'sjis2.txt'; open(IN, "<$infile"); @lines = <IN>; close(IN); open(OU, ">$outfile"); print OU @lines; close(OU); 3)SJIJSで以下のスクリプトを作成します #=== two.pl === use encoding 'Shift_JIS'; use open IN => ":encoding(Shift_JIS)"; use open OUT => ":encoding(Shift_JIS)"; my $infile = 'sjis2.txt'; my $outfile = 'sjis3.txt'; open(IN, "<$infile"); @lines = <IN>; close(IN); open(OU, ">$outfile"); print @lines; close(OU); 4)one.pl を実行し、続いてtwo.plを実行すると 以下のエラーがコマンドプロンプトに表示されます。 #------------------------------------------- D:\zipcode\utf8mondai>two.pl Wide character in print at D:\zipcode\utf8mondai\two.pl line 14. "・趣セゑスカ・イ・・セ橸スウ" Wide character in print at D:\zipcode\utf8mondai\two.pl line 14. "蛹玲オキ驕・ これは何故なのでしょうか。 エラーメッセージは、printしようとしている 文字列にutf8フラグがついているという意味 らしいです。

    • ベストアンサー
    • Perl
  • テキストを参照としたPerlによる名前の変更

    よろしくお願いします。ディレクトリ内のファイル名をテキストデータを参照として変更したいと思っております。まず、以下の参照テキストがあります。 sansyo.txt 1,2,1 2,3,1 3,4,2 4,5,3 6,7,9 ・ ・ ・ ・ このファイルを利用してディレクトリ内のファイルを以下のようにリネームします。 1,2.txt → 1,2,1.txt 2,3.txt → 2,3,1.txt 3,4.txt → 3,4,2.txt 4,5.txt → 4,5,3.txt 6,7.txt → 6,7,9.txt ・ ・ ・ ・ ・ ここで私は以下のプログラムを作成しました。 sansyo.pl ------------------------------ use strict; use warnings; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); print $dir, "\n"; open(FILE, $dir) or die "$dir: $!"; open(FILE2,"sansyo.txt"); my @file = <FILE>; my @file2 = <FILE2>; close(FILE); close(FILE2); foreach my $line2 (@file2) { my ($a,$b,$c) = split(/,/, $line2); if ($dir == $a.",".$b.".txt"){ rename ($dir, $a.",".$b.",".$c.".txt"); } } } closedir(DIR); 内容は、FILE2にsansyo.txtをforeachで1行ずつ読み込んでいき、 $a,$b.txtというファイルが$dirに読み込んだファイルにあったら、 $a,$b,$c.txtというファイルにリネームするという内容です。 ですが、いろいろ試行錯誤したもののうまくいきません。 具体的には、 Argument "1,2.txt" isn't numeric in numeric eq (==) at sansyo.pl line 23. とエラーがでて if ($dir == $a.",".$b.".txt"){ この部分でエラーが発生しているようです。 どなたか解決方法をよろしくお願いします。

    • ベストアンサー
    • Perl
  • 特定の数字を抜いて、行をずらしたいです。

    0 1 2 3 4      9 8 7 6 5 6 5 4 3 2 7 8 6 9 2 8 0 9 8 1   ↓ 0 1 2 6 4 9 8 7 3 5 6 5 4 9 2 7 8 6 8 2 8 0 9 最初の行のひとつの数字(左から4つ目:3)を抜いて、行をずらしたいのですが、つまづいています。 open (IN,"< $ARGV[0].csv") or die; open (OUT,"> $ARGV[0]_out.csv") or die; ####################################################### while($line =<IN>){ ($a, $b, $c, $d, $e) = split(/\s+/,$line); if($d == "3"){ $d == "" } print OUT (////////\n); } 分割してから、3を抜いてずらしたいのですがうまくいきません。 お助けいただきたく、どうぞよろしくお願い致します。

    • ベストアンサー
    • Perl
  • Perlでのファイル入出力、処理方法

    メモ帳で以下のようなプログラムを書きました。(file_1.plで保存しました) #!/usr/bin/perl $file="data.csv"; $cityfile="name.txt"; $outfile="data_out.csv"; open (IN, $file) or die "$!"; open (FILE, $file) or die "$!"; open (OUT, ">$outfile") or die "$!"; @city = <FILE>; ・ ・ ・ これをCygwinコマンド上で、 perl file_1.pl と入力し、Enterを押すと「No such file or directory at file_1.pl line 9.」と表示されます。 line9はopen (FILE, $file) or die "$!";という文です。 どこが間違えで、どのように修正すればよいのでしょうか。 よろしくお願いします。

  • ディレクトリ内のテキストファイルに対する同一処理

    よろしくお願いします。現在Linuxの環境でテキスト処理をしております。 ディレクトリ内にファイル名の異なった以下のような大量ファイルがあります。 a.txt 0,1,2,3,4,5,6,7 1,2,3,4,5,6,7,8 b.txt 2,3,4,5,6,7,8,9 3,4,5,6,7,8,9,10 これらのファイルをカンマでsplitし、左から2番目の数にだけ1を引き,下のディレクトリであるoutに出力させます。出力は以下のようになります。 ./out/a.txt 0,0,2,3,4,5,6,7 1,2,3,4,5,6,7,8 ./out/b.txt 2,2,4,5,6,7,8,9 3,4,5,6,7,8,9,10 そこで以下のようなPerlのプログラムを作成しました。 use strict; use warnings; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); print $dir, "\n"; open(FILE, $dir) or die "$dir: $!"; my @file = <FILE>; foreach $line (@file) { my ($a,$b,$c,$d,$e,$f,$g,$h) = split(/,/, $line);      my $b = $b - 1; close(FILE); } open(NEWFILE, "> ./out/$dir") or die "$dir: $!"; print NEWFILE @file; close(NEWFILE); } closedir(DIR); ですが、出力は完了するのですが、元のファイルから計算がされていません。どこがどう間違えているのかご指摘よろしくお願い申し上げます。

    • ベストアンサー
    • Perl
  • perl初心者です。宜しくお願い致します。

    ファイルの容量が大きく。perlを使用してデータの集計をしています。 "A"がきたらflag1をたてなさい。 "B"がきたらflag2をたてなさい。 "C"がきたらflag3をたてなさい。 これでAとBとCを抜き取ること&AからCまでの時間を取得したのですが、 Bの数のmaxの値だけを抜き取りたいのですが、Bがきたときの数をすべて 出力してしまいます。下記の文だと、Bが4回きたら、1,2,3,4と出力してしまいます。 それで4だけを出力したいのですがどのように書き換えたらようか教えて頂けますでしょうか。 '----------------------------------------------------------------------------- open (IN,"< $ARGV[0].txt") or die; open (OUT,"> $ARGV[0]_out.txt") or die; $flag =0; my $a, $b, $c; $count = 0; ####################################################### while($line =<IN>){ ($time,$data) = split(/\s+/,$line); if($data eq "A") { $flag=1; $a = $time; #print OUT $line; #print OUT "\n"; } elsif($data eq "B"){ $flag=2; $count++; $count == $data; print OUT ("$count\n") } #print OUT ("$count\n"); elsif($data eq "C"){ $flag=0; $count=0; $b = $time; $c = $b - $a; print OUT ("time $c\n") } } -------------------------------------------------------------------------------

  • 下のディレクトリ(3つ)に含まれる同じファイル名のテキストを結合し,カレントディレクトリに出力する

    いつもお世話になっております.環境はWindows XPのActiveperlです. やりたいことは「下のディレクトリ(3つ)に含まれる同じファイル名のテキストを結合し,カレントディレクトリに出力する」ことです.具体的にはいかのようにしたいと思っています. 現在のディレクトリ/a/1.txt a b c 現在のディレクトリ/b/1.txt d e f 現在のディレクトリ/c/1.txt g h i 現在のディレクトリ/1.txt a b c d e f g h i ここで私は以下のプログラムを作成しました. use strict; use warnings; my $dirname1 = './a/'; my $dirname2 = './b/'; my $dirname3 = './c/'; opendir(DIR1, $dirname1) or die "$dirname1: $!"; while (my $dir1 = readdir(DIR1)) { next unless (-f $dir1); next unless ($dir1 =~ /\.txt$/); opendir(DIR2, $dirname2) or die "$dirname2: $!"; while (my $dir2 = readdir(DIR2)) { next unless (-f $dir2); next unless ($dir2 =~ /\.txt$/); opendir(DIR3, $dirname3) or die "$dirname3: $!"; while (my $dir3 = readdir(DIR3)) { next unless (-f $dir3); next unless ($dir3 =~ /\.txt$/); if (($dir1 == $dir2) && ($dir2 == $dir3)){ open(FILE1, $dir1) or die "$dir1: $!"; my $line1 = <FILE1>; close(FILE1); open(FILE2, $dir2) or die "$dir2: $!"; my $line2 = <FILE2>; close(FILE2); open(FILE3, $dir3) or die "$dir3: $!"; my $line3 = <FILE3>; close(FILE3); my $joint_line = $line1.$line2.$line3; open(NEWFILE, "> $dir1") or die "$dir1: $!"; print NEWFILE $joint_line; close(NEWFILE); } } } } closedir(DIR1); closedir(DIR2); closedir(DIR3); ですが,以下のようなエラーが発生しています. closedir() attempted on invalid dirhandle DIR2 at joint.pl line 51. closedir() attempted on invalid dirhandle DIR3 at joint.pl line 52. ディレクトリハンドルが使われているけれど閉じているか実際にはディレクトリハンドルでは無い時にこれらの警告が発行されるとこの警告がでるようですが,どのようにしたら解決できるのでしょうか.よろしくお願いします.

専門家に質問してみよう