【问题标题】:How can I strip all comments from a Perl script except for the shebang line?如何从 Perl 脚本中删除除 shebang 行之外的所有注释?
【发布时间】:2020-04-17 23:27:34
【问题描述】:

我有一个从其他 Perl 脚本中剥离 cmets 的 Perl 脚本:

open (INFILE, $file);
@data = <INFILE>;

foreach $data (@data)
{
    $data =~ s/#.*/ /g;
    print "$data";
}

问题是,这段代码还删除了 shebang 行:

#!/usr/bin/perl

除了shebang,我怎样才能剥离cmets?

【问题讨论】:

  • 您可以简单地创建一个名为$skip 的变量,其值为1。代码第一次进入循环,如果$skip等于1,则将值改为0,continue
  • 你的代码也会像$#array这样剥离代码,这不是注释。
  • 谢谢你,先生,但我真的很想跳过第一次出现而不是第一行..
  • @tidibur shebang 不能在第一行以外的任何其他行。
  • 后来怎么样了?你有没有告诉你的老师他是个菜鸟? :)

标签: regex perl


【解决方案1】:

编写代码来剥离 cmets 并非易事,因为# 字符可用于除 cmets 之外的其他上下文。请改用perltidy

perltidy --delete-block-comments --delete-side-comments foo

将从文件foo 中删除# cmets(但不是POD)并将输出写入foo.tdy。 shebang 没有被剥离。

【讨论】:

  • @tidibur 我想要一匹小马。正则表达式不能胜任这项任务,你在浪费时间去尝试。由于字符串引用等原因,您甚至无法使用正则表达式可靠地处理琐碎的情况。
  • @tidibur 然后你必须编写一个正则表达式来解释可以使用# 的所有不同上下文:block cmets (# foo), side cmets (my $foo; # foo),字符串(my $foo = '#foo';my $foo = q/#foo/; 等)、here-docs、数组(my $last = $#array;)等等。不要重新发明轮子(很糟糕)。
  • @ThisSuitIsBlackNot 我尝试使用它来跳过第一次出现:foreach $data(@data) { $data =~ s/#(?!\!\/)//g; print "$data"; } 虽然我能够保存路径不被删除,但以下出现仅删除了“#”而不是整个评论。
  • @tidibur 这是一个无用的考试,由一个不懂 Perl 的老师创建。这个问题非常复杂,充满了边缘情况。即使是像你这样微不足道的正则表达式也会对 Perl 代码造成极大的破坏。您必须限制注释的样式,例如/^# /(首先在线,然后是空格)。但即使这样也可能以无数种方式失败,例如多行字符串或正则表达式。告诉你的老师,他会印象深刻的。或者受到侮辱,但是,嘿,yolo。
  • @tidibur,ThisSuitIsBlackNot 的“复杂”意味着“页面和页面长”。专家写作需要数周时间。我同意 TLP。写那次考试的人犯了一个错误。我能不能让你觉得无法处理 shebang 行是不可接受的,但认为无法处理 $#array"#"s#/#!##line 1000 等是可以接受的。你的程序将无法在你自己的程序上运行!
【解决方案2】:

有一个方法PPR::decomment()可以使用:

use strict;
use warnings;
use PPR;

my $document = <<'EOF';
print "\n###################################\n";
print '\n###################################\n';
print '\nFollowed by comment \n'; # The comment
return $function && $function !~ /^[\s{}#]/;
EOF

my $res = PPR::decomment( $document );
print $res;

输出

print "\n###################################\n";
print '\n###################################\n';
print '\nFollowed by comment \n'; 
return $function && $function !~ /^[\s{}#]/;

【讨论】:

  • 看起来不错,但是当我在一个变量中包含字符串并在循环文件时如何使用它?
  • 您可以尝试在变量上运行PPR::decomment()
  • 抱歉唠叨(作为非 perl 程序员),但如果说字符串在 $cleanline 中,我该怎么做?
  • 没问题。你试过PPR::docomment( $cleanline ) 吗?
  • 我刚刚发送了我的唠叨评论,然后我看到了 $res 行,所以我只想写评论:哦,愚蠢的我,只是 my $res = PPR::decomment( $cleanline);。测试需要一些时间,我可能要安装 PPR
【解决方案3】:

perltidy 是执行此操作的方法,如果它不是练习的话。还有PPI 用于解析perl。可以使用PPI::Token::Comment 令牌做一些比剥离更复杂的事情。

但是,要回答您的直接问题,请不要尝试在单个正则表达式中解决所有问题。相反,将您的问题分解为信息和逻辑的逻辑片段。相反,如果您想跳过第一行,请使用逐行处理来执行此操作,该处理可以方便地在$ 中设置当前行号。

use strict;
use warnings;
use autodie;

my $file = '... your file...';

open my $fh, '<', $file;

while (<$fh>) {
    if ($. != 1) {
        s/#.*//;
    }

    print;
}

免责声明

正如大家已经说过的那样,使用正则表达式解决这个问题的方法肯定是有缺陷的。但是,我要让您的讲师受益,并且她/他的目标是通过故意给您一个超出正则表达式能力范围的问题来进行教学。很好看,找到所有这些边缘情况并弄清楚如何处理它们。

无论您做什么,都不要尝试使用单个正则表达式来解决它们。分解你的问题并使用大量的if's 和elsif's

【讨论】:

  • 除了破坏$#array"#"s#/#!#g#line 1000的明显问题之外,它不会删除第一行的cmets(如果有的话)。
  • 我应该说“除了程序无法自行运行的明显问题”!
  • @Miller 简短但干净的代码。做得很好,但如果 shebang 放在第二行,这将不起作用。尽管它应该始终是第一的纯粹常识。生病试一试。谢谢
  • @tidbur,你错了。第二行不可能有shebang之类的东西。根据定义,shebang (#!) 必须是文件的前两个字符。
  • 我的解决方案并不是一个“解决方案”。它旨在建议一种解决此问题的方法,但您肯定需要添加更多逻辑。无论如何,离开这个,因为我只是想向你的教练明显打算的方向轻推。
【解决方案4】:

既然您要求使用正则表达式解决方案:

'' =~ /(?{
   system("perltidy", "--delete-block-comments", "--delete-side-comments", $file);
   die "Can't launch perltidy: $!\n"                   if $? == -1;
   die "perltidy killed by signal ".( $? & 0x7F )."\n" if $? & 0x7F;
   die "perltidy exited with error ".( $? >> 8 )."\n"  if $? >> 8;
});

您似乎倾向于使用以下内容:

#!/usr/bin/perl
while (<>) {
   if ($. != 1) {
      s/#.*//;
   }
   print;
}

但它对自己不起作用:

$ chmod u+x stripper.pl

$ stripper.pl stripper.pl >stripped_stripper.pl

$ chmod u+x stripped_stripper.pl

$ stripped_stripper.pl stripper.pl
Substitution pattern not terminated at ./stripped_stripper.pl line 4.

$ cat stripped_stripper.pl
#!/usr/bin/perl
while (<>) {
   if ($. != 1) {
      s/
   }
   print;
}

第一行删除cmets也失败:

$ cat >first.pl
# This is my first Perl program!
print "Hello, World!\n";

$ stripper.pl first.pl
# This is my first Perl program!
print "Hello, World!\n";

【讨论】:

  • 感谢您的帮助,但这种方式太复杂了,我无法理解。我才学习 perl 大约一个星期。
  • 它的作用与没有第一行和最后一行的情况完全相同:它运行 perltidy,并抛出并报告任何错误。你坚持它必须在一个正则表达式中,所以你去。如果你不能理解,你怎么可能写一个 Perl 解析器?
  • 是的。对此感到抱歉。我希望@miller 的解决方案就足够了。并感谢您的努力。 :)
  • @Miller 的解决方案不适用于 Miller 的解决方案。
  • 我试过了,它奏效了。但前提是“shebang”在第一行.. 嗯
猜你喜欢
  • 2019-07-04
  • 2012-06-07
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 2020-08-01
  • 2018-10-27
  • 2016-02-29
相关资源
最近更新 更多