有时我想通过在某个地方输出它来处理Perl字符串异常,该异常的末尾带有"at File.pm line 123"。然而,我真的不想用路径名、行号等来公开最后一位。
随着时间的推移,我想出了几个可能的解决方案,但我都不太喜欢。仅仅使用这样的正则表达式就是一个明显的例子:
s/s+ at s+ .*$//xms;
但问题是,它会杀死任何带有"at"字样的东西。将行号设为非可选有帮助,但最终你会发现匿名代码中有"at ANON"或类似的怪异内容。
我甚至尝试过这样的东西:
$_ = reverse $_;
s/^.*? s+ ta s+//xms;
$_ = reverse $_;
它对单行错误非常有效。但是,如果您最终得到了来自confess
或其他异常抛出器的完整堆栈跟踪,那么您最终得到的是长堆栈跟踪。
有人想分享一个好的解决方案吗?还是一个更好的方法的建议?("不要那样输出死亡信息"不是一个可以接受的答案。)
如果有一个CPAN模块我忽略了,我很想知道。如果没有,我正在考虑为此贡献一个CPAN模块。
-
您的第一个片段不是«杀死任何带有"at"字样的东西;。
at
必须是它做任何事情的倒数第二个词。 -
我认为你的两个片段(正向和反向)是100%等效的(除了第二个不支持尾随换行,所以它可能永远不会匹配)。
-
图案
/s+ at s+ S+ (?:s+ line s+ d+)?$/x
不会匹配
$ perl -e'(eval "sub { die }")->()' Died at (eval 1) line 1.
-
图案
/s+ at s+ S+ (?:s+ line s+ d+)?$/x
不会匹配
$ echo foo | perl -e'<STDIN>; die;' Died at -e line 1, <STDIN> line 1.
-
我认为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
输出总是包含at
和line
部分,所以应该足够使用:
s/s+ats(?!.*batb).*slinesd+.$//;