みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

テキストを参照とした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"){
この部分でエラーが発生しているようです。

どなたか解決方法をよろしくお願いします。

投稿日時 - 2008-07-17 20:56:26

QNo.4184378

すぐに回答ほしいです

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

すみません, 言い忘れていたことがあります.
ロジックとしては間違っていない (かもしれない) ですが, 「普通の書き方」ではないです.
まず, ファイル sansyo.txt をディレクトリに存在する全てのファイルに対して毎回読み直してますが, 普通に考えたらこれは無意味です. 最初に 1回だけ読めばいいはず.
また, eq で比較するのではなく, sansyo.txt の内容から適切なハッシュを作るのが常道でしょう.
まとめると, 最初に
my %cvt;
open(FILE2,"sansyo.txt");
for my $line (<FILE2>) {
chomp($line);
my ($a, $b, $c) = split(/,/, $line);
$cvt{"$a,$b.txt"} = "$line.txt";
}
として「$cvt{リネーム前} = リネーム後」という形でハッシュ %cvt を作っておき, あとは
for my $dir (readdir(DIR)) {
next unless -f $dir;
rename($dir, $cvt{$dir}) if defined $cvt{$dir};
}
とするのが普通じゃないかなぁ.

投稿日時 - 2008-07-18 11:21:24

お礼

Tacosan様、pick52様

ご回答ありがとうございました。別件で多忙だったため、コメントが遅れました。なるほど、確かに無駄なプロセスを組み込んでいましたね。どうも初心者なもので、今ある知識だけで組んだものなので非常に勉強になりました。感謝いたします。

投稿日時 - 2008-07-18 13:58:54

ANo.5

このQ&Aは役に立ちましたか?

87人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

>>Tacosanさん
> grep じゃなくて glob>#2

そのようですね。
すみません、間違えました。ご指摘ありがとうございます。
ActivePerlなどでも内部的にバッチで対応しているみたいですね。

返信ついでに調べてみるとディレクトリ内のファイル検索方法って
他にもいくつかあるみたいですね。

http://perl-mongers.org/2008/05/opendirglobfilefindrule.html

投稿日時 - 2008-07-18 03:20:38

ANo.3

grep じゃなくて glob>#2.
でも, なんでリネームしようとしているファイルの中身を読んでるんだろう. しかも使ってないし.

投稿日時 - 2008-07-18 00:21:42

ANo.2

関係ないのですがファイル名に半角カンマって使用できたんですね。
でもあまり使用しない方がいいような気も。

実はディレクトリないのファイル名はopendirを使用しなくても

while(<*>) {
print "$_\n";
}

これで取得できたりします。
(これって確かgrep関数の省略形だったような気が...)

# 微妙にopendirと動作が異なるので注意
# 1. カレントディレクトリ(.)と親ディレクトリ(..)は取得されません
# 2. 絶対パスまたは相対パスで指定するとその部分まで取得されます
# 他にもあるかも
# なので適材適所で使用した方がいいでしょう
# (上記の方法の方が簡単だけどopendirの方がより厳密に操作できる)

投稿日時 - 2008-07-17 22:49:42

ANo.1

文字列の等価比較は == じゃなくて eq.

投稿日時 - 2008-07-17 21:29:53

あなたにオススメの質問