Learning Perlの第 9 章「正規表現を使用したテキストの処理」に取り組んでいます。
以下は、章の終わりの演習の 2 つです。
これまでのすべての演習の回答に著作権行を追加するプログラムを作成し
## Copyright (c) 20XX by Yours Truly
、「shebang」行の直後にファイルのような行を配置します。コマンド ラインで既に編集するファイル名を使用してプログラムが呼び出されると想定します。以前のプログラムを変更して、著作権行が既に含まれているファイルを編集しないようにします。そのヒントとして、ダイヤモンド オペレーターによって読み取られるファイルの名前が $ARGV にあることを知っておく必要があるかもしれません。
これは私の試みた解決策でした:
#!/usr/bin/env perl
use 5.014;
use warnings;
my $shebang = '(#!/usr/bin/env perl|#!/usr/bin/perl)';
my $copyright = '# Copyright (c) 20XX Yours Truly';
$^I = ".bak";
while (<>) {
unless (/$copyright/mi) {
s/($shebang)/$1\n$copyright/mig;
}
print;
}
を使用してコマンド ラインで実行しますperl ch9.pl sample_perl_script.pl
。
私の目標は次のとおりです。
- パスに関係なく、元のシバンをそのまま保持します。
- 1 回だけループし
<>
ます。 - 著作権表示が存在するかどうかを確認します。
- そうでない場合は、追加します(したがって、 で試行し
unless { ... }
ます)。
これは、問題の最初の部分 (著作権行の追加) では機能しますが、2 番目の部分 (著作権がまだ存在していないことを確認してください) では機能しません。
私の質問は次のとおりです。なぜですか?そしてunless
、プログラムを実行すると完全に無視されるのはなぜですか?
付録をのぞき見したところ、この本の提案された解決策は、ファイル名を追跡するためのハッシュを作成し、ファイルを2 回$ARGV
渡すことでした。最初に著作権表示のあるファイルを削除してから、検索/置換を実行します。そのようです:
my %do_these;
foreach (@ARGV) {
$do_these{$_} = 1;
}
while (<>) {
if (/\A## Copyright/) {
delete $do_these{$ARGV};
}
}
@ARGV = sort keys %do_these;
$^I = ".bak";
while (<>) {
if (/\A#!/) {
$_ .= "## Copyright (c) 20XX by Yours Truly\n";
}
print;
}
もちろん、これは機能しますが、2 倍の作業のように思えます。私のアプローチを使用して、単一のwhile (<>) { ... }
ループ内でこれを行う方法があるかどうかを確認し、ダイヤモンド演算子がどのように機能するかをよりよく理解できるようにしようとしています。
私のアプローチが完全に的外れである場合は、その理由を説明してください。私の気持ちを惜しまないでください。私は自分のエゴよりも完全な理解に関心があります。