電子書籍の厳選無料作品が豊富!

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

A 回答 (11件中1~10件)

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

この回答への補足

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

補足日時:2008/08/04 16:55
    • good
    • 0
この回答へのお礼

pick52様

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

お礼日時:2008/08/04 16:31

まだ締め切られていないようなのでぺたり。



#!/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);
}


要素数の短いものに合わせて切り詰めます・
    • good
    • 0
この回答へのお礼

sakusaker7様

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

お礼日時:2008/08/04 23:38

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

    • good
    • 0
この回答へのお礼

tacosan様

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

お礼日時:2008/08/04 23:33

>>No.7,8さん



面白いですね。
いろいろな書き方ができるのがPerlの面白いところ、魅力(すばらしい
ところ)ですね。
どれが早いか・効率がいいかなどは分かりませんけど。

逆に勉強になりました。
    • good
    • 0
この回答へのお礼

pick52様

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

お礼日時:2008/08/04 16:50

無意味に短くしてみる試み:


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 ってコマンドがあれば簡単なんだけどね....
    • good
    • 0
この回答へのお礼

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.

兎にも角にもありがとうございました.

お礼日時:2008/08/04 16:48

如何でしょうか。


----------------
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;
}
    • good
    • 0
この回答へのお礼

_--_--_-_-様

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

お礼日時:2008/08/04 16:43

>>No.3


もう一つバグ発見。

my @file = <FILE>;

とした後、他の変数にバックアップとっておかないとまずいですね。
(テストしたときはファイルが一つだけだったので複数ファイルがある
ことを考慮していませんでした)
その辺りは頑張って修正してください。

他にも問題があるかも。

この回答への補足

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

補足日時:2008/08/04 11:32
    • good
    • 0

>>No.3


あ、

print @file;

はデバッグ時のものです。
除去し忘れていましたが不要なので削除してください。
    • good
    • 0

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

たびたび申し訳ありませんが,なにとぞよろしくお願いします.

補足日時:2008/08/04 11:13
    • good
    • 0

その処理をしたいなら, foreach ループをネストさせちゃダメ. たのしいことになります.


他にも
・@file, @file2 の両方を print してるのはなぜ?
・$line に対する代入のクォートは適切ですか?
くらいは気になるなぁ.

この回答への補足

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

補足日時:2008/08/04 00:34
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!