我们有一些非常老的Perl代码最近一次更新是在1997年。我正在尝试升级到$*不推荐使用的新Perl版本。
我一直在尝试学习如何重写它,但是从perlvar文档中获得的唯一帮助是“您应该使用/ s和/ m regexp修饰符。”
my ($file, $regexp, $flags) = @_;
my (@found_lines, @tmp_list, $comp_buf);
local ($*);
if ($flags =~ tr/c//d)
{
$* = 1;
(substr ($regexp, 0, 1) ne "^") && ($regexp = "^.*$regexp");
($regexp !~ /([^\\]|^)(\\\\)*\$$/) && ($regexp .= ".*\$");
&read_comp ($file, \$comp_buf);
@found_lines = grep ($_ .= "\n", ($comp_buf =~ /$regexp/g));
}
else
{
@tmp_list = &read_list ($file, 0);
@found_lines = grep (/$regexp/, @tmp_list);
}
if ($flags eq "q")
{
$#found_lines >= 0;
}
elsif ($flags eq "a")
{
$#found_lines+1;
}
else
{
@found_lines;
}
Run Code Online (Sandbox Code Playgroud)
$*从我$*在这里使用的注释中了解的内容来看,要为以下正则表达式搜索启用多行匹配,真的很难知道如何为我替换。所以我猜我必须以某种方式将这些标志添加到regexp表达式中。
如何重写此代码以替换现有$*实例?
mel*_*ene 10
不幸的$*是,它是一个全局变量,因此,read_comp如果使用正则表达式,对其进行设置会影响所有调用的函数(例如)。
同样,该代码以一种奇怪的方式编写:
我以为是要为该$comp_buf =~ /$regexp/g零件启用“多行”匹配,但$*设置较早,因此也会影响$regexp !~ /([^\\]|^)(\\\\)*\$$/和read_comp调用。
检查是否$regexp已经分别以^/ 开头/结尾$被破坏。例如,(?:^foo$)是锚定的正则表达式,但是代码无法检测到。
grep ($_ .= "\n", ...)是grep对模仿的莫名其妙的滥用map。代码试图做的是获取正则表达式匹配的行列表。但是,正则表达式的构建方式与"\n"每一行上的终止换行符都不匹配,因此该代码将手动添加"\n"到每个返回的字符串中。
这样做的理智方式是:
@found_lines = map $_ . "\n", ...; # or map "$_\n", ...
Run Code Online (Sandbox Code Playgroud)
取而代之的是,map我们利用命令循环for别名为当前列表元素的事实,使用命令式循环:
@temp = ...;
for (@temp) {
$_ .= "\n";
}
@found_lines = @temp;
Run Code Online (Sandbox Code Playgroud)
除了for循环之外,我们还可以使用grep其遍历列表的副作用:
@temp = ...;
grep $_ .= "\n", @temp;
@found_lines = @temp;
Run Code Online (Sandbox Code Playgroud)
grep也是$_当前元素的别名,因此“过滤器表达式”可以修改我们要遍历的列表。
最后,因为.=返回结果字符串(且包含的字符串"\n"不能为false),所以我们可以利用以下事实:我们的“过滤器表达式”始终返回一个真值,并有效地从以下位置获取输入列表的副本作为返回值grep:
@found_lines = grep $_ .= "\n", ... # blergh
Run Code Online (Sandbox Code Playgroud)至于的效果$*:它是一个布尔标志(最初为false)。如果设置为true,所有的正则表达式表现得好像/m是有效的,即^和$比赛在嵌入式换行符以及字符串的开始/结束。
假设我对代码的解释是正确的,则应该可以进行如下更改:
local ($*); 可以删除。$* = 1; 还需要走。$comp_buf =~ /$regexp/g应该更改为$comp_buf =~ /$regexp/mg。这是我看到的唯一的多行模式有意义的地方。我真的很想重写最后一行。要么
@found_lines = map "$_\n", ($comp_buf =~ /$regexp/g);
Run Code Online (Sandbox Code Playgroud)
(实用样式),或者,如果您更喜欢命令式样式:
@found_lines = ($comp_buf =~ /$regexp/g);
$_ .= "\n" for @found_lines;
Run Code Online (Sandbox Code Playgroud)