我正在学习 Perl的第 9 章“使用正则表达式处理文本”。
以下是两章结尾的练习:
编写一个程序,为到目前为止的所有练习答案添加版权行,
## 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
.
我的目标是:
- 无论路径如何,都保持原始 shebang 完整。
- 只循环
<>
一次。 - 检查版权声明是否存在。
- 如果没有,请添加它(因此尝试使用
unless { ... }
)。
这适用于问题的第一部分(添加版权行),但不适用于第二部分(检查以确保版权不存在)。
我的问题是:为什么?为什么unless
我运行程序时完全忽略了?
我看了看附录,书中提出的解决方案是创建一个哈希来跟踪文件名$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;
}
这当然有效,但似乎是工作的两倍。我正在尝试使用我的方法来查看是否有办法在单个while (<>) { ... }
循环中执行此操作,并更好地了解菱形运算符的工作原理。
如果我的方法完全偏离基础,请解释原因,不要吝啬我的感受。我对完全理解比我的自我更感兴趣。