質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

Q&A

解決済

1回答

2147閲覧

[Perl]複数のファイルにそれぞれ違う内容を書き込む方法について

Oi_daki

総合スコア1

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

0グッド

0クリップ

投稿2020/05/22 01:16

[Perl]複数のファイルに違う内容を書き込む

Perlを使って複数ファイルにそれぞれ違う内容を書き込みたいです。

具体的には、コマンドライン入力した$start_no=2、入力ファイルの行数が 3 とすると
tmp1.txtに 2 3 4 5
tmp2.txtに 6 7 8 9
....
と書き込みたいです。

以下のコードでは、指定した出力ファイルtmp1~4.txt自体はつくられますが、中にはなにも書き込まれません。
余分と判断した部分は削除しているため、入力ファイル内の値はここでは何も使われていません。

該当のソースコード

Perl

1my $infile=$ARGV[0]; 2my $start_no=$ARGV[1]; 3 4open (my $infh,'<',$infile); 5 6my $i=0; 7my $j; 8for ($j=1;$j<5;$j++){ 9 my $outfile1="tmp1.txt"; 10 my $outfile2="tmp2.txt"; 11 my $outfile3="tmp3.txt"; 12 my $outfile4="tmp4.txt"; 13 14 open (my $outfl1,'>',$outfile1); 15 open (my $outfl2,'>',$outfile2); 16 open (my $outfl3,'>',$outfile3); 17 open (my $outfl4,'>',$outfile4); 18 while ( my $line= <$infh>) { 19 $i++; 20 if ($i == 1){ 21 next;#skip label 22 } 23 24 my $line_no1=2*($start_no-2)+2; 25 my $line_no2=$line_no1+1; 26 if($j==1){ 27 print $outfl1 "$line_no1 \n"; 28 print $outfl1 "$line_no2 \n"; 29 } 30 elsif($j==2){ 31 print $outfl2 "$line_no1 \n"; 32 print $outfl2 " $line_no2 \n"; 33 } 34 elsif($j==3){ 35 print $outfl3 "$line_no1 \n"; 36 print $outfl3 "$line_no2 \n"; 37 } 38 else{ 39 print $outfl4 "$line_no1 \n"; 40 print $outfl4 " $line_no2 \n"; 41 } 42 $start_no++; 43 } 44 close ($outfl1); 45 close ($outfl2); 46 close ($outfl3); 47 close ($outfl4); 48} 49close ($infh);

試したこと

出力ファイルに書き込む前に print $outfl1; とすると、GLOB(0x2208c38) と表示されます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

回答を大幅に修正しました。

1.オープンのモードについて
添え字jのループ内でopen~closeしていますが、オープンモードが毎回 ">"なのでファイルが毎回トランケートされてしまいますね。
">>"に変更すれば良いかと。

2.正しいインデントを(これに惑わされました)

Perl

1 while ( my $line= <$infh>) { 2 $i++; 3 if ($i == 1){ 4 next;#skip label 5 }

最後のブレスは一見whileの終わりに見えますが、whileループ内のif分の終わりです。
これでは1回目のforループで入力ファイルを全て読み終わって、全て出力ファイル1に書き込んで
しまいます。
2回目以降のforループは入力ファイルが既にEOFなので空振りするだけです。

インデントは正しく書きましょう。

投稿2020/05/22 01:35

編集2020/05/22 05:38
DreamTheater

総合スコア1095

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Oi_daki

2020/05/22 01:52

返信ありがとうございます! 実際、ファイルハンドルであることは意識せずmy $outfl1という書き方をしていましたが、openが問題なのは変わりないということですか?
DreamTheater

2020/05/22 03:55

ファイルが生成されていることからopen自体は問題なりですね。
DreamTheater

2020/05/22 03:58

回答欄に追記しましたが、openのモードの問題ですね。
Oi_daki

2020/05/22 04:18

open (my $outfl1,'>>',$outfile1); ... とだけ変更しましたが、結果は変わらずでした。 書き忘れていましたが、tmp1.txtだけは中身までしっかり書き込まれる、というのも不可解な点です。(whileが問題?) 今までのアドバイスですでに非常にありがたいのですが、また何かあったら追記していただけると嬉しいです。
DreamTheater

2020/05/22 04:53

while ( my $line= <$infh>) { $i++; if ($i == 1){ next;#skip label } 最後のブレスは一見whileの終わりに見えますが、whileループ内のif分の終わりですよ。 これでは1回目のforループで入力ファイルを全て読み終わって、全て出力ファイル1に書き込んで しまいます。 2回目以降のforループは入力ファイルが既にEOFなので空振りするだけです。 インデントは正しく書きましょう。
Oi_daki

2020/05/22 05:45

すみません、丁寧に書くべきでした。そして丁寧にご指摘ありがとうございます。 そもそも私の設計ミスだったようです。 理想では、<while文で入力ファイルを全て読み込む>という動作をfor文を使って4回行いたかったのです。 最初のforでEOFに到達するため、このコードではそうならないということですよね?? また、そうするにはどう変更したら良いでしょうか。
DreamTheater

2020/05/22 06:11

入力ファイルは行数のみ意味があるということですよね?(しかも1行目はラベル) 1)配列変数に入力ファイルを一気に読み込む。 2)配列の要素数ー1が、1ファイル当たりの列数となる。 3)forループを4回回して、それぞれ回数に相当するファイルを書き込みモードで開く。 4)3のループ内で番号の初期値から列数分回るforループを作る。 5)内側のループ内で番号をファイルに出力する。 6)内側のループを終了したら出力ファイルをクローズする。 こんな感じの実装にすれば良いと思います。 コードで書くこともできますが、コピペされるだけなら勉強になりませんよ。 がんばってください。
Oi_daki

2020/05/22 06:16

わかりました。その方針で組み立ててみます。 たくさんのコメント、大変勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問