プロが教える店舗&オフィスのセキュリティ対策術

こんにちは。Perl(超?)初心者です。

フォルダ内にあるファイルの名前を、「filename_ja.txt」という形式から「filename_en.txt」に変更するスクリプトを書こうとしているのですが、エラーになってうまくいきません。

環境は、Windows XP professional SP3とActivePerl 5.10 で、以下のように記述しました。

use strict;
use warnings;

my @filename = glob "*.txt";
foreach my $oldname(@filename) {

my $newname = $oldname;
$newname = ~s/(.+)_ja\.txt/$1_en\.txt/;
rename ($oldname,$newname);
}

これを実行すると、「Use of uninitialized value $_ in substitution (s///) at test_5.pl line 8.」とエラーメッセージが出て、フォルダ内のテキストファイルが消失してしまいます。

また、以下のようにも書いてみたのですが、やはりうまくいきません。
この場合は、エラーこそ出ないものの、なにも起こりません。

use strict;
use warnings;

for(<\.txt>) {

my $old=$_;
s/(.+)_ja\.txt/$1_en\.txt/;
rename($old,$_);
}

初歩的な質問で申し訳ありませんが、ダメな生徒にアドヴァイスを与えるつもりで、スクリプトを添削していただけるとありがたいです。

よろしくお願いします。

A 回答 (3件)

$1_en\.txt を、 ${1}_en\.txt に代えたらどうでしょう?



一般的に、 "" や m// の様な変数と文字列を混在して書ける所では、変数名の終りを意識せずに書くと後続の文字列も含めて変数名と解釈される場合があります。 そのときは、上記の様に変数名を {} で囲みましょう。


ところで...

> $newname = ~s/(.+)_ja\.txt/$1_en\.txt/;

= と ~ の間に空白は、本当は無いんですよね?

「=~」はひとつの演算子で、途中の空白は無い方が良いです。 「=~」の前後には、空白がある方が良いです。


ところで その2

$newname =~ s/_ja\.txt$/_en\.txt/;

の方が良いと思いますよ。
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございました。

ご指摘のとおり、= と ~ の間にスペースがあり、ついでに =~ の後ろにスペースがありませんでした。ここを直したら、意図したとおりに動きました。

ところで、ファイル名を変更したいファイルは「en」というファルダに入っているのですが、このフォルダ名を引っ張ってきて、「_ja.txt」を「_en.txt」にすることは初心者にも可能でしょうか。

というのも、C:\foldername\en、C:\foldername\de、C:\foldername\frという3つのフォルダに大量のファイルが格納されていて、それぞれ「en」フォルダのファイルは「_en.text」に、「de」は「_de.txt」に、「fr」は「_fr.txt」にファイル名を変更する必要があるのです。

これを処理するスクリプトは、初心者にはハードルが高すぎるでしょうか。

想像するに、C:\foldername 以下のディレクトリ名を取得して、そこから最後の2文字を切り出して、それを配列やら変数やらに代入してなどなど、難しそうな作業が満載のような気がします。

お礼日時:2009/12/15 18:36

条件の後出しは(スクリプト書く上で)非常に嫌われるので、最初に出来る限り出しておいたほうがいいですよ。



use strict;
use warnings;
use File::Copy;

my $dir = "C:/foldername";
my @langs = qw/en de fr/;

foreach my $lang (@langs) {
while (my $file = glob "$dir/$lang/*.txt") {
my $rename = $file;
$rename =~ s/_jp\.txt$/_$lang.txt/;
move ($file, $rename);
}
}
    • good
    • 0

> 初心者にも可能でしょうか。



やりたい事がもっと詳細かつ具体的に分らないと何とも言えませんね。 Perl初心者というよりプログラミング初心者ならなおさらです。

・C:\foldername は例なんでしょうが、1個だけか沢山あるのか?

・対象ファイルは、C:\foldername/*/ 直下のみかサブディレクトリ下にもあるのか?


まずは、 glob に絶対パスを渡して簡単になりませんか?

glob "C:/foldername/en/*_ja.txt"
とか
glob "C:/foldername/*/*_ja.txt"
    • good
    • 0
この回答へのお礼

ご助言ありがとうございます。

glob に絶対パスを渡すこともできるのですね。
それなら、

my @filename = glob "C:/foldername/en/*_ja.txt"
<ファイル名変更の処理>
my @filename = glob "C:/foldername/de/*_ja.txt"
<ファイル名変更の処理>
my @filename = glob "C:/foldername/fr/*_ja.txt"
<ファイル名変更の処理>

のように、重ねていけばいけそうな気がします。
土臭いやり方ですけど。

お礼日時:2009/12/17 00:06

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