1

有时我想通过在某处输出它来处理末尾带有“at File.pm line 123”的 Perl 字符串异常。但是,我真的不想用路径名、行号等公开最后一位。

随着时间的推移,我提出了几种可能的解决方案,但我都不太喜欢它们。仅使用这样的正则表达式是一个显而易见的表达式:

s/\s+ at \s+ .*$//xms;

但问题是它会杀死任何带有“at”字样的东西。将行号设为非可选会有所帮助,但最终您会得到具有“at ANON”的匿名代码或类似的怪诞代码。

我什至尝试过这样的事情:

$_ = reverse $_;
s/^.*? \s+ ta \s+//xms;
$_ = reverse $_;

这对单行错误非常有效。但是,如果您最终得到来自confess或其他异常抛出器的完整堆栈跟踪,那么您最终会得到长堆栈跟踪。

有人愿意分享一个好的解决方案吗?或者更好的方法的建议?(“不要像那样输出 die 消息”不是可接受的答案。)

如果有一个我忽略的 CPAN 模块在这里提供帮助,我很想知道。如果没有,我正在考虑为此目的贡献一个 CPAN 模块。

4

3 回答 3

4
  1. 您的第一个片段不会«杀死任何带有“ at”一词的东西。»。at必须是倒数第二个字才能做任何事情。

  2. 我认为你的两个片段(正向和反向)是 100% 等效的(除了第二个不支持尾随换行符,所以它可能永远不会匹配)。

  3. 图案

    /\s+ at \s+ \S+ (?:\s+ line \s+ \d+)?$/x
    

    不匹配

    $ perl -e'(eval "sub { die }")->()'
    Died at (eval 1) line 1.
    
  4. 图案

    /\s+ at \s+ \S+ (?:\s+ line \s+ \d+)?$/x
    

    不匹配

    $ echo foo | perl -e'<STDIN>; die;'
    Died at -e line 1, <STDIN> line 1.
    
  5. 我认为 Perl 不会在不添加数字的情况下添加文件名。

    如果行号是可选的,那么您将不可避免地匹配“晚餐在九点”的最后两个单词。除非您开始采用启发式方法。


查看源代码,这是die可以附加的:

Adds:                   " at %s line %"IVdf
Sometimes followed by:  ", <%"SVf"> line %"IVdf
                or by:  ", <%"SVf"> chunk %"IVdf
Sometimes followed by:  " during global destruction"
Always followed by:     ".\n"

这给了我们:

s/
   (?&BASE)
   (?&IO_CLAUSE)?
   (?&GLOBAL_DESTR)?
   \.?\n\z

   (?(DEFINE)
      (?<BASE>         [ ] at [ ] (?&FILE_NAME) [ ] line [ ] [0-9]+ )
      (?<IO_CLAUSE>    , [ ] <(?&HANDLE_NAME)> [ ] (?:line|chunk) [ ] [0-9]+ )
      (?<GLOBAL_DESTR> [ ]during[ ]global[ ]destruction )

      # Heuristics:
      (?<FILE_NAME>   \S+ | \(eval[ ][0-9]+\) )
      (?<HANDLE_NAME> \w+ )
   )
//x

这是尽可能具体的。

(注意:据.我所知,Carp 有时会忘记尾随的“”。)

(注意:Perl 使用单个空格,因此[ ]比 . 更精确\s+。)

于 2012-09-26T19:54:12.257 回答
2

die您可以通过定义一个函数来覆盖您的内置CORE::GLOBAL::die函数:

BEGIN {
    *CORE::GLOBAL::die = sub {
        my $y = pop @_;
        chomp $y;
        CORE::die @_,$y,"\n";
    }
}

my $method = rand(3);
die "I died\n" if $method > 2;
die "I died too" if $method > 1;
die;

报告要么

I died
I died too
<nothing - maybe not the right thing to do>

如何使用该CORE::GLOBAL::...软件包记录在perlsub.

于 2012-09-26T20:56:28.117 回答
0

我相信标准die输出总是包含atline部分,所以它应该足够使用:

s/\s+at\s(?!.*\bat\b).*\sline\s\d+\.$//;
于 2012-09-26T19:51:54.237 回答