11.7 練習問題1

第11章[ファイルハンドルとファイルテスト]の練習問題1へ。

ユーザから入力ファイル名、出力ファイル名、サーチパターン、置き換え文字列を入力して貰う様なプログラムを書いてください。
はじめてのPerl P.199

まずは自作解答です。

#! /usr/local/bin/perl

use strict;
use warnings;


#このプログラムの説明をユーザに伝える
print "指定元ファイルから、サーチパターンにマッチした文字列を指定した文字列に置き換え、それを指定先のファイルに書き換えるプログラムです。\n";

#入力ファイルを入力
print "指定元ファイルのパスを入力してください。\n";
chomp(my $input_file = <STDIN>);

#出力ファイルを入力
print "指定先ファイルのパスを入力してください。\n";
chomp(my $output_file = <STDIN>);

#サーチパターンを入力
print "サーチしたい文字列を指定してください。\n";
chomp(my $search_pattern = <STDIN>);

#置き換え文字列を入力
print "マッチした文字列に置き換えたい文字列を指定してください。\n";
chomp(my $substitute_pattern = <STDIN>);

#入力用ファイルハンドラをopen
open INPUT, "< $input_file"
    or die "cannot open the file! ($!)";

#出力用ファイルハンドラをopen
open OUTPUT, ">$output_file"
    or die "cannot open the file! ($!)";

#while命令で1つずつ読み、置換する
while(<INPUT>) {
    s/$search_pattern/$substitute_pattern/g; #変数$_に対して置換を行う
    print OUTPUT;                            #変数$_を出力ファイルに出力する
}

#ファイルハンドラをクローズする
close INPUT;
close OUTPUT;

下記のtes1.txtというファイルを用いて、

jkondo
reikon
naoya
kawasaki
onishi

このプログラムを実行してみます。

C:\Perl\hajip>perl hoge.pl
指定元ファイルから、サーチパターンにマッチした文字列を特定の文字列に置き換え、それを指定先のファイルに書き換えるプログラムです。
指定元ファイルのパスを入力してください。
tes1.txt
指定先ファイルのパスを入力してください。
tes2.txt
指定元ファイルの置き換えたい文字列を指定してください。
kon
サーチパターンにマッチした文字列を、何に置き換えるか、文字列を入力してください。
KON

C:\Perl\hajip>type tes2.txt
jKONdo
reiKON
naoya
kawasaki
onishi

機能上の問題はなさそうですね。


さらに解答を見て、いけてなかった部分を箇条書きにしてみます。

  • ユーザにメッセージを出力し、入力を求める部分はサブルーチン化する。

全部で4つも同じ機能を書いてますね。無駄。

  • ファイルの指定が行われたら、すぐさまファイルハンドラをオープンする。

これによって、無効なファイル名だった場合の時間の無駄がなくなる、と。
(これについては、コメント欄でid:kidd-number5さんが言うように、ロックの問題が発生してしまう。ファイルが存在しなければdieするのが最良か。)

  • 出力ファイルを上書きしてしまうのを防ぐために、ファイルテスト-eで判断する


それじゃあ書き直しと行きますか。

#! /usr/local/bin/perl

use strict;
use warnings;


#入力受付サブルーチン
sub get_input {
    print $_[0];
    chomp(my $input = <STDIN>);
    return $input;
}


#このプログラムの説明をユーザに伝える
print "指定元ファイルから、サーチパターンにマッチした文字列を指定した文字列に置き換え、それを指定先のファイルに書き換えるプログラムです。\n";

#入力ファイルを入力、即ファイルハンドラをオープンする
my $input_file = get_input("指定元ファイルのパスを入力してください。\n");
open INPUT, $input_file
    or die "入力用ファイル '$input_file' を開けませんでした。 ($!)";

#出力ファイルを入力
my $output_file = get_input("指定先ファイルのパスを入力してください。\n追加書き込みしたいときは、パス名の最初に\">\"を入力してください。\n");
die "出力用ファイル '$output_file'は既に存在しています。\n"
    if -e $output_file;

open OUTPUT, ">$output_file"
    or die "出力用ファイル '$output_file' を開けませんでした。 ($!)";

#サーチパターンを入力
my $search_pattern = get_input("サーチしたい文字列を指定してください。\n");

#置き換え文字列を入力
my $substitute_pattern = get_input("マッチした文字列に置き換えたい文字列を指定してください。\n");


#while命令で1つずつ読み、置換する
while(<INPUT>) {
    s/$search_pattern/$substitute_pattern/g; #変数$_に対して置換を行う
    print OUTPUT;                            #変数$_を出力ファイルに出力する
}

#ファイルハンドラをクローズする
close INPUT;
close OUTPUT;


ところでこのソースコードはいくらなんでもコメント付けすぎでしょうか?
長期間の保守作業が必要な場合には、たくさんコメントを書くのが良いというのはわかりますが、コメントをつける加減がイマイチわからないのです。