Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 如何从Perl文件中读取自定义模式?_Regex_Perl_Logging - Fatal编程技术网

Regex 如何从Perl文件中读取自定义模式?

Regex 如何从Perl文件中读取自定义模式?,regex,perl,logging,Regex,Perl,Logging,预祝大家新年快乐 我有一个错误日志文件,其中包含模式参数、结果和stderr(stderr可以有多行)中的内容 $cat错误\u日志 :测试总数 :1 :预期“测试总数=2”,实际值为3 测试总数=3 :测试一次计数 :0 :应为“测试计数=2”,实际值为0 测试一个计数=0 :测试两次计数 :4 :应为“test_two_count=2”,实际值为4 测试二计数=4 ... 我需要用Perl编写一个函数,将每个参数、结果和stderr存储在数组或哈希表中 这是我们自己内部定义的结构。我这样编

预祝大家新年快乐

我有一个错误日志文件,其中包含模式参数、结果和stderr(stderr可以有多行)中的内容

$cat错误\u日志
:测试总数
:1
:预期“测试总数=2”,实际值为3
测试总数=3
:测试一次计数
:0
:应为“测试计数=2”,实际值为0
测试一个计数=0
:测试两次计数
:4
:应为“test_two_count=2”,实际值为4
测试二计数=4
...
我需要用Perl编写一个函数,将每个参数、结果和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;
 }
my$err_msg=”“;
而()
{
如果(/:/)
{
s/:/;
推送@参数,$\;
}
elsif(/:/)
{
s/:/;
按@结果,$\;
}
elsif(/:/)
{
如果(长度($err_msg)>0)
{
推送@stderr,$err_msg;
}
s/:/;
$err\u msg=$\u;
}
其他的
{
$err_msg.=$\uu;
}
} 
如果(长度($err_msg)>0)
{
推送@stderr,$err_msg;
}
看起来不错。=)一个改进可能是将这些标记锚定在行的开头:

if (/^<parameter>:/)
if(/^:/)
这将使脚本更加健壮

如果捕捉到标签后面的内容并仅使用该部分,也可以避免标签剥离:

if (/^<parameter>:(.*)/s)
{
  push @parameter, $1;
}
if(/^:(.*)/s)
{
按@参数,$1;
}

重构的主要内容是匹配、剥离和存储过程中的重复。类似这样(未经测试)的代码更简洁:

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;
my($err\u msg,%data);
而(){
如果((我的$key)=$=~s/^://){
如果($key eq'stderr'){
推送{$data{$key}},$err_msg if$err_msg;
$err\u msg=$\u;
}
else{push@{$data{$key},$}
}
else{$err\u msg.=$\u0}
}
#从料斗中取出最后一个错误消息
推送{$data{stderr}},$err_msg;

。。。但六个月后可能更难理解。。。8^)

如果您使用的是Perl 5.10,那么您可以做一些与现在非常类似的事情,但是通过使用给定的/when结构,布局会更好:

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$_" }
    }
}
在这里,当我们看到一个字段时,我们将一个新记录推送到数组中,每当我们看到一个键/值对时,我们都会在哈希中添加一个条目,如果我们看到一个延续行,我们会将其追加到我们添加到的最后一个字段中。
@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},
    }
)
现在,您可以只传递一个包含所有记录的数据结构,将来可以添加更多字段(甚至是多行字段),这些字段将得到正确处理

如果您没有使用Perl5.10,那么这可能是升级的好借口。如果没有,您可以将给定的/when结构转换为更传统的If/elsif/else结构,但它们在转换过程中失去了许多美丽


保罗

谢谢,我错过了验证:-)我喜欢第一个。这是一个很好的、紧凑的重构+1第二个更好。如果您使用的是perl 5.10,为什么现在要使用命名捕获,例如当(m{^:(?*)}x{$records[-1]{$+{key}}=$+{value};$prev_key=$+{key};}它使代码稍微长一点,但避免了不舒服的硬编码$1和$2引用。感谢您的解决方案。我们使用的是PerlV5.8.5。我使用if-else实现了包含哈希表概念的数组代码。它帮助我更多地理解了Perl中的数组概念,而且还减少了代码中的行数。
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$_";     }
    }
}
(
    {
        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},
    }
)