- ベストアンサー
一つのテキストファイルと複数のファイルの結合
よろしくお願いします.ディレクトリ内の一つのテキストファイル(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);
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
>>No.3 > 早速実行してみたところ,最初のファイルは思ったように処理される > のですが,2つ目のファイル以降は処理されたファイルが前回の > ファイルの内容を引き継ぎ,その後に出力されてしまいます. > 具体的には以下の内容です. 結局修正してみました。 以下のような感じです。 use File::Basename; my $dirname = '.'; die('not open : joint.txt') unless(open(FILE, 'joint.txt')); my $file = join('', <FILE>); close(FILE); while(<$dirname/*.txt>) { my $fn = (fileparse($_))[0]; next if($fn eq 'joint.txt'); my @file = split(/\n/, $file); if(open(FILE, $_)) { my @file2 = <FILE>; for(my $i = 0; $i <= $#file2; $i++) { $file[$i] .= ",$file2[$i]"; } close(FILE); if(open(FILE, ">$_")) { print FILE @file; close(FILE); } } } あと、今回の場合は関係ないのですがNo.2とNo.3で提示されたイメージ 内容が逆のような気がするのですが。(^_^; 例外的なことは殆ど考えていないので実際にはいろいろ修正する必要が 出てくると思いますけど、そこまで考慮できなくてすみません。
その他の回答 (10)
- sakusaker7
- ベストアンサー率62% (800/1280)
まだ締め切られていないようなのでぺたり。 #!/usr/bin/perl # -*- coding: utf8 -* use strict; use warnings; use Fatal qw(:void open close); use feature ':5.10'; use File::Slurp qw/slurp read_file write_file/; use List::MoreUtils qw/all each_array/; my $dirname = '.'; my $joint_file = 'joint.txt'; my @files = grep {$_ !~ /$joint_file/} glob "$dirname/*.txt"; my @joint_base = slurp($joint_file); chomp @joint_base; foreach my $file (@files) { my @lines = slurp($file); my $it = each_array @joint_base, @lines; my @newlines; while (my @l = $it->()) { push @newlines, join(q{,}, @l) if all {defined $_} @l; } write_file($file . ".new" , @newlines); } File::Slurp とか List::MoreUtilsがない場合用。 #!/usr/bin/perl # -*- coding: utf8 -* use strict; use warnings; use Fatal qw(:void open close); use feature ':5.10'; sub slurp { my $file = shift; open my $fh, '<', $file or return; <$fh>; } sub write_file { my $file = shift; open my $fh, '>', $file or warn "can't ooen $file"; print $fh @_; } my $dirname = '.'; my $joint_file = 'joint.txt'; my @files = grep {$_ !~ /$joint_file/} glob "$dirname/*.txt"; open my $fh, '<', $joint_file; #open my $fh, '<', $joint_file; or die "could not open $joint_file by $!"; my @joint_base = <$fh>; close $fh; chomp @joint_base; foreach my $file (@files) { my @lines = slurp($file); my @newlines; my $min = @lines < @joint_base ? @lines : @joint_base; foreach my $i (0 .. $min-1) { push @newlines, join(q{,}, $joint_base[$i], $lines[$i]); } write_file($file . ".new" , @newlines); } 要素数の短いものに合わせて切り詰めます・
お礼
sakusaker7様 ご回答ありがとうございます。場合分けまでしただいてありがとうございます。今は実行環境にないため、明日実行させていただきます。 そろそろ、回答を締め切りますね。 今回は、11個の回答を頂けました。大変感謝しております。 みなさん、ありがとうございました。 このような処理は多くの方がしたいと思っていると思うので、 今後はこの内容が検索で引っかかるといいと思っております。
- Tacosan
- ベストアンサー率23% (3656/15482)
あ~, 2箇所 die を dir と typo してますね>#8.
お礼
tacosan様 ご回答ありがとうございました。 処理が通りました。毎度のことながらありがとうございます。
- pick52
- ベストアンサー率35% (166/466)
>>No.7,8さん 面白いですね。 いろいろな書き方ができるのがPerlの面白いところ、魅力(すばらしい ところ)ですね。 どれが早いか・効率がいいかなどは分かりませんけど。 逆に勉強になりました。
お礼
pick52様 そうですね.初心者ながらPerlの処理の楽しさに魅了されております.
- Tacosan
- ベストアンサー率23% (3656/15482)
無意味に短くしてみる試み: open FILE, './joint.txt' or die "joint.txt: $!"; chomp(my @header = <FILE>); close FILE; my $dirname = '.'; opendir DIR, $dirname or die "$dirname: $!"; my @files = grep { /\.txt$/ && $_ ne 'joint.txt' } readdir DIR; closedir(DIR); for my $file (@files) { open FILE, $file or dir "$file: $!"; my @lines = <FILE>; close FILE; open NEWFILE, ">$file" or dir "$file: $!"; print NEWFILE map {"$header[$_],$lines[$_]" } 0 .. $#lines; close NEWFILE; } つなげたい 2つのファイルの行数が違うときにどうしたらいいかはしらん. paste ってコマンドがあれば簡単なんだけどね....
お礼
Activeperl上で実行してみたところ以下のエラーがでました. String found where operator expected at joint.pl line 11, near "dir "$file: $!" " (Do you need to predeclare dir?) String found where operator expected at joint.pl line 14, near "dir "$file: $!" " (Do you need to predeclare dir?) syntax error at joint.pl line 11, near "dir "$file: $!"" syntax error at joint.pl line 14, near "dir "$file: $!"" Execution of joint.pl aborted due to compilation errors. 兎にも角にもありがとうございました.
- _--_--_-_-
- ベストアンサー率47% (8/17)
如何でしょうか。 ---------------- my $dirname = './'; my $filename = './joint.txt'; open my $file, $filename or die "$filename: $!\n"; my @content = <$file>; close $file; chomp @content; while (my $line = <$dirname*.txt>) { next if $line eq $filename; open my $file, $line or die "$line: $!\n"; my @try = <$file>; close $file; chomp @try; open my $newfile, '>', $line or die "$line: $!\n"; for (my $i = 0; $i < @content; $i ++) { last unless defined $try[$i]; print $newfile "$content[$i],$try[$i]\n"; } close $newfile; }
お礼
_--_--_-_-様 ご回答ありがとうございます.問題なく通りました.感謝いたします.
- pick52
- ベストアンサー率35% (166/466)
>>No.3 もう一つバグ発見。 my @file = <FILE>; とした後、他の変数にバックアップとっておかないとまずいですね。 (テストしたときはファイルが一つだけだったので複数ファイルがある ことを考慮していませんでした) その辺りは頑張って修正してください。 他にも問題があるかも。
補足
こちらのご回答を見忘れていました.頑張って修正してみます.
- pick52
- ベストアンサー率35% (166/466)
>>No.3 あ、 print @file; はデバッグ時のものです。 除去し忘れていましたが不要なので削除してください。
- pick52
- ベストアンサー率35% (166/466)
use File::Basename; my $dirname = '.'; die('not open : joint.txt') unless(open(FILE, 'joint.txt')); my @file = <FILE>; close(FILE); while(<$dirname/*.txt>) { my $fn = (fileparse($_))[0]; next if($fn eq 'joint.txt'); if(open(FILE, $_)) { my @file2 = <FILE>; for(my $i = 0; $i <= $#file2; $i++) { chomp($file[$i]); $file[$i] .= ",$file2[$i]"; } close(FILE); print @file; if(open(FILE, ">$_")) { print FILE @file; close(FILE); } } } こんな感じでどうでしょうか。 ファイルが開けなかったときのエラー処理まではしていませんけど。
補足
pick52様 ご回答ありがとうございます.先日はお世話になりました. 早速実行してみたところ,最初のファイルは思ったように処理されるのですが,2つ目のファイル以降は処理されたファイルが前回のファイルの内容を引き継ぎ,その後に出力されてしまいます.具体的には以下の内容です. joint.txt ------------------- a b c d e 1.txt ---------------------- a,1 b,2 c,3 d,4 e,5 2.txt ---------------------- a,1a,1 b,2b,2 c,3c,3 d,4d,4 e,5e,5 たびたび申し訳ありませんが,なにとぞよろしくお願いします.
- Tacosan
- ベストアンサー率23% (3656/15482)
その処理をしたいなら, foreach ループをネストさせちゃダメ. たのしいことになります. 他にも ・@file, @file2 の両方を print してるのはなぜ? ・$line に対する代入のクォートは適切ですか? くらいは気になるなぁ.
補足
ご回答ありがとうございました。今日中に仕上げたかったのですが、何とも知識不足で進みません。明日、また取り組みたいと思います。
- Tacosan
- ベストアンサー率23% (3656/15482)
「うまくいかない」とはどういう状態をさしているのでしょうか? 簡単な例を挙げて「期待した動作」と「現実の動作」を説明していただけませんか?
補足
Tacosan様,いつもお世話になっております. 言葉足らずですみませんでした. 期待した動作は以下になります. joint.txt -------------------- 1 2 3 4 5 ・ ・ ・ ・ ・ ディレクトリ内のテキストファイル --------------------------------- a b c d e ・ ・ ・ ・ ・ 処理後のディレクトリ内のテキストファイル --------------------------------- 1,a 2,b 3,c 4,d 5,e ・ ・ ・ ・ ・ ------------------------------------------ 現実の動作 プログラムを実行しても変化がありません. よろしくお願い申し上げます.
お礼
pick52様 ご回答ありがとうございました.実行したところ処理がうまく通りました. pick52様には以前もご回答いただきましたね.毎度のことながら大変感謝をしております.
補足
あ,逆になってましたね.すみません. 正確に書かなければ,回答者の方に混乱をきたしてしまうことを 肝に銘じて今後は注意します.