为所有人带来新年祝福。
我有一个错误日志文件,其中包含模式参数,结果和stderr中的内容(stderr可以是多行)。
$cat error_log
<parameter>:test_tot_count
<result>:1
<stderr>:Expected "test_tot_count=2" and the actual value is 3
test_tot_count = 3
<parameter>:test_one_count
<result>:0
<stderr>:Expected "test_one_count=2" and the actual value is 0
test_one_count = 0
<parameter>:test_two_count
<result>:4
<stderr>:Expected "test_two_count=2" and the actual value is 4
test_two_count = 4
...
我需要在Perl中编写一个函数来将每个参数,result和stderr存储在数组或哈希表中。
这是我们自己内部定义的结构。我写了这样的Perl函数。使用正则表达式本身有更好的方法吗?
my $err_msg = "";
while (<ERR_LOG>)
{
if (/<parameter>:/)
{
s/<parameter>://;
push @parameter, $_;
}
elsif (/<result>:/)
{
s/<result>://;
push @result, $_;
}
elsif (/<stderr>:/)
{
if (length($err_msg) > 0)
{
push @stderr, $err_msg;
}
s/<stderr>://;
$err_msg = $_;
}
else
{
$err_msg .= $_;
}
}
if (length($err_msg) > 0)
{
push @stderr, $err_msg;
}
答案 0 :(得分:4)
如果您使用的是Perl 5.10,那么您可以使用给定/何时结构,执行与现在非常相似但具有更好布局的内容:
use 5.010;
while (<ERR_LOG>) {
chomp;
given ($_) {
when ( m{^<parameter>: (.*)}x ) { push @parameter, $1 }
when ( m{^<result>: (.*)}x ) { push @result, $1 }
when ( m{^<stderr>: (.*)}x ) { push @stderr, $1 }
default { $stderr[-1] .= "\n$_" }
}
}
值得注意的是,对于此处的默认情况,我只是在看到@stderr
标记并追加到最后一项时,只是推送stderr
而不是保留单独的$ err_msg变量。如果我看到一个延续线,则为@stderr
数组。我在看到延续线时添加换行符,因为我假设你想要保留它们。
尽管上面的代码看起来非常优雅,但我并非真的所有喜欢保留三个独立阵列的人,因为如果事情不同步,它可能会让你头疼,因为如果你想要在未来添加更多字段,最终会有很多变量浮动,你需要跟踪它们。我建议将每条记录存储在一个哈希中,然后保留一组记录:
use 5.010;
my @records;
my $prev_key;
while (<ERR_LOG>) {
chomp;
given ($_) {
when ( m{^<parameter> }x ) { push(@records, {}); continue; }
when ( m{^<(\w+)>: (.*)}x ) { $records[-1]{$1} = $2; $prev_key = $1; }
default { $records[-1]{$prev_key} .= "\n$_"; }
}
}
这里我们在看到一个字段时将新记录推送到数组上,每当我们看到一个键/值对时向我们的哈希添加一个条目,如果我们看到一个延续线,则追加到我们添加的最后一个字段。 @records
的最终结果如下:
(
{
parameter => 'test_one_count',
result => 0,
stderr => qq{Expected "test_one_count=2" and the actual value is 0\ntest_one_count=0},
},
{
parameter => 'test_two_count',
result => 4,
stderr => qq{Expected "test_two_count=2" and the actual value is 4\ntest_two_count=4},
}
)
现在,您只能传递包含所有记录的单个数据结构,并且您可以在将来添加更多字段(即使是多行字段),也可以正确处理它们。
如果你没有使用Perl 5.10,那么这可能是升级的一个很好的借口。如果没有,您可以将给定/何时结构转换为更传统的if / elsif / else结构,但它们在转换中失去了很多美感。
保
答案 1 :(得分:3)
重构的主要因素是重构,剥离和存储。像这样(未经测试的)代码更简洁:
my( $err_msg , %data );
while (<ERR_LOG>) {
if(( my $key ) = $_ =~ s/^<(parameter|result|stderr)>:// ) {
if( $key eq 'stderr' ) {
push @{ $data{$key} } , $err_msg if $err_msg;
$err_msg = $_;
}
else { push @{ $data{$key} } , $_ }
}
else { $err_msg .= $_ }
}
# grab the last err_msg out of the hopper
push @{ $data{stderr} } , $err_msg;
......但是从现在起六个月后可能更难理解...... 8 ^)
答案 2 :(得分:1)
看起来不错。 =)改进可能是将这些标记锚在行的开头:
if (/^<parameter>:/)
它会使脚本更加健壮。
如果您抓住标签之后的内容并仅使用该部分,您也可以避免剥离标签:
if (/^<parameter>:(.*)/s)
{
push @parameter, $1;
}