• ベストアンサー

一つのテキストファイルと複数のファイルの結合

よろしくお願いします.ディレクトリ内の一つのテキストファイル(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);

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

  • ベストアンサー
  • pick52
  • ベストアンサー率35% (166/466)
回答No.6

>>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で提示されたイメージ 内容が逆のような気がするのですが。(^_^; 例外的なことは殆ど考えていないので実際にはいろいろ修正する必要が 出てくると思いますけど、そこまで考慮できなくてすみません。

oswll
質問者

お礼

pick52様 ご回答ありがとうございました.実行したところ処理がうまく通りました. pick52様には以前もご回答いただきましたね.毎度のことながら大変感謝をしております.

oswll
質問者

補足

あ,逆になってましたね.すみません. 正確に書かなければ,回答者の方に混乱をきたしてしまうことを 肝に銘じて今後は注意します.

その他の回答 (10)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.11

まだ締め切られていないようなのでぺたり。 #!/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); } 要素数の短いものに合わせて切り詰めます・

oswll
質問者

お礼

sakusaker7様 ご回答ありがとうございます。場合分けまでしただいてありがとうございます。今は実行環境にないため、明日実行させていただきます。 そろそろ、回答を締め切りますね。 今回は、11個の回答を頂けました。大変感謝しております。 みなさん、ありがとうございました。 このような処理は多くの方がしたいと思っていると思うので、 今後はこの内容が検索で引っかかるといいと思っております。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.10

あ~, 2箇所 die を dir と typo してますね>#8.

oswll
質問者

お礼

tacosan様 ご回答ありがとうございました。 処理が通りました。毎度のことながらありがとうございます。

  • pick52
  • ベストアンサー率35% (166/466)
回答No.9

>>No.7,8さん 面白いですね。 いろいろな書き方ができるのがPerlの面白いところ、魅力(すばらしい ところ)ですね。 どれが早いか・効率がいいかなどは分かりませんけど。 逆に勉強になりました。

oswll
質問者

お礼

pick52様 そうですね.初心者ながらPerlの処理の楽しさに魅了されております.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

無意味に短くしてみる試み: 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 ってコマンドがあれば簡単なんだけどね....

oswll
質問者

お礼

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. 兎にも角にもありがとうございました.

回答No.7

如何でしょうか。 ---------------- 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; }

oswll
質問者

お礼

_--_--_-_-様 ご回答ありがとうございます.問題なく通りました.感謝いたします.

  • pick52
  • ベストアンサー率35% (166/466)
回答No.5

>>No.3 もう一つバグ発見。 my @file = <FILE>; とした後、他の変数にバックアップとっておかないとまずいですね。 (テストしたときはファイルが一つだけだったので複数ファイルがある ことを考慮していませんでした) その辺りは頑張って修正してください。 他にも問題があるかも。

oswll
質問者

補足

こちらのご回答を見忘れていました.頑張って修正してみます.

  • pick52
  • ベストアンサー率35% (166/466)
回答No.4

>>No.3 あ、 print @file; はデバッグ時のものです。 除去し忘れていましたが不要なので削除してください。

  • pick52
  • ベストアンサー率35% (166/466)
回答No.3

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); } } } こんな感じでどうでしょうか。 ファイルが開けなかったときのエラー処理まではしていませんけど。

oswll
質問者

補足

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)
回答No.2

その処理をしたいなら, foreach ループをネストさせちゃダメ. たのしいことになります. 他にも ・@file, @file2 の両方を print してるのはなぜ? ・$line に対する代入のクォートは適切ですか? くらいは気になるなぁ.

oswll
質問者

補足

ご回答ありがとうございました。今日中に仕上げたかったのですが、何とも知識不足で進みません。明日、また取り組みたいと思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「うまくいかない」とはどういう状態をさしているのでしょうか? 簡単な例を挙げて「期待した動作」と「現実の動作」を説明していただけませんか?

oswll
質問者

補足

Tacosan様,いつもお世話になっております. 言葉足らずですみませんでした. 期待した動作は以下になります. joint.txt -------------------- 1 2 3 4 5 ・ ・ ・ ・ ・ ディレクトリ内のテキストファイル --------------------------------- a b c d e ・ ・ ・ ・ ・ 処理後のディレクトリ内のテキストファイル --------------------------------- 1,a 2,b 3,c 4,d 5,e ・ ・ ・ ・ ・ ------------------------------------------ 現実の動作 プログラムを実行しても変化がありません. よろしくお願い申し上げます.

関連するQ&A