gpt4 book ai didi

perl - 使用弃用的 $* 重写旧程序

转载 作者:行者123 更新时间:2023-12-04 10:59:47 26 4
gpt4 key购买 nike

我们有一些非常旧的 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;
}

真的很难知道怎么更换 $*对我来说,根据我从我们使用的评论中可以理解的内容 $*此处为以下正则表达式搜索启用多行匹配。所以我猜我必须以某种方式将这些标志添加到正则表达式表达式中。

如何重写此代码以替换现有的 $*实例?

最佳答案

不幸的是 $* 是一个全局变量,所以如果它们使用正则表达式,设置它会对所有被调用的函数(例如 read_comp )产生影响。

此外,该代码的编写方式有点奇怪:

  • 我认为目的是为 $comp_buf =~ /$regexp/g 部分启用“多行”匹配,但 $* 设置较早,因此它也会影响 $regexp !~ /([^\\]|^)(\\\\)*\$$/read_comp 调用。
  • 检查 $regexp 是否已经分别以 ^/$ 开始/结束的检查被破坏。例如,(?:^foo$) 是一个 anchor 定的正则表达式,但代码不会检测到它。
  • grep ($_ .= "\n", ...) 是一种莫名其妙的滥用 grep 来模拟 map 。代码试图做的是获取正则表达式匹配的行列表。但是,正则表达式的构建方式与每一行的终止换行符 "\n" 不匹配,因此代码手动将 "\n" 添加到每个返回的字符串中。

    这样做的明智方法是:
    @found_lines = map $_ . "\n", ...;   # or map "$_\n", ...

    我们可以使用命令式循环代替 map,利用 for 将循环变量别名为当前列表元素的事实:
    @temp = ...;
    for (@temp) {
    $_ .= "\n";
    }
    @found_lines = @temp;

    我们可以使用 for 代替 grep 循环,因为它有迭代列表的副作用:
    @temp = ...;
    grep $_ .= "\n", @temp;
    @found_lines = @temp;
    grep 还将 $_ 别名为当前元素,因此“过滤器表达式”可以修改我们正在迭代的列表。

    最后,因为 .= 返回结果字符串(并且包含 "\n" 的字符串不能为假),我们可以利用我们的“过滤器表达式”总是返回真值的事实,并有效地获取输入列表的副本作为从grep:
    @found_lines = grep $_ .= "\n", ...  # blergh

  • 至于 $* 的效果:它是一个 bool 标志(最初为假)。如果设置为 true,则所有正则表达式都表现为 /m 有效,即 ^$ 匹配嵌入的换行符以及字符串的开头/结尾。

    假设我对代码的解释是正确的,您应该能够按如下方式更改它:
  • local ($*); 可以删除。
  • $* = 1; 也需要去。
  • $comp_buf =~ /$regexp/g 应更改为 $comp_buf =~ /$regexp/mg 。这是我看到的唯一一个多行模式有意义的地方。
  • 我真的很想重写最后一行。任何一个
    @found_lines = map "$_\n", ($comp_buf =~ /$regexp/g);

    (功能风格),或者,如果您更喜欢命令式风格:
    @found_lines = ($comp_buf =~ /$regexp/g);
    $_ .= "\n" for @found_lines;
  • 关于perl - 使用弃用的 $* 重写旧程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58166262/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com