消毒模具串、去除" at File.pm line 123"的可靠方法是什么?



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

随着时间的推移,我想出了几个可能的解决方案,但我都不太喜欢。仅仅使用这样的正则表达式就是一个明显的例子:

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

但问题是,它会杀死任何带有"at"字样的东西。将行号设为非可选有帮助,但最终你会发现匿名代码中有"at ANON"或类似的怪异内容。

我甚至尝试过这样的东西:

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

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

有人想分享一个好的解决方案吗?还是一个更好的方法的建议?("不要那样输出死亡信息"不是一个可以接受的答案。)

如果有一个CPAN模块我忽略了,我很想知道。如果没有,我正在考虑为此贡献一个CPAN模块。

  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)?
.?nz
(?(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

这是尽可能具体的。

(注意:据我所知,鲤鱼有时会忘记后面的"."。)

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

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

BEGIN {
*CORE::GLOBAL::die = sub {
my $y = pop @_;
chomp $y;
CORE::die @_,$y,"n";
}
}
my $method = rand(3);
die "I diedn" if $method > 2;
die "I died too" if $method > 1;
die;

报告任一

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

perlsub中记录了如何使用CORE::GLOBAL::...软件包。

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

s/s+ats(?!.*batb).*slinesd+.$//;

最新更新