【问题标题】:Perl: parsing text output into array of hashesPerl:将文本输出解析为哈希数组
【发布时间】:2021-02-27 22:07:07
【问题描述】:

我没有经验,也不太擅长编写代码,而且我已经在这个问题上停留了一段时间。我之前搜索过stackoverflow,但找不到任何与我的问题相匹配的东西,所以想尝试通过这种方式获得一些帮助。

我想构建一个脚本来分析某个命令的文本输出并将其放入哈希数组中,这样我就可以用它来做一些事情了。

我有这样的文本输出:

      1 : DISPLAY AUTHREC GROUP('GROUP1')
 AMQ8864I: Display authority record details.
    PROFILE(SYSTEM.ADMIN.COMMAND.QUEUE)     ENTITY(GROUP1)
    ENTTYPE(GROUP)                          OBJTYPE(QUEUE)
    AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT)
 AMQ8864I: Display authority record details.
    PROFILE(SYSTEM.MQEXPLORER.REPLY.MODEL)
    ENTITY(GROUP1)                         ENTTYPE(GROUP)
    OBJTYPE(QUEUE)
    AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT)
 AMQ8864I: Display authority record details.
    PROFILE(self)                           ENTITY(GROUP1)
    ENTTYPE(GROUP)                          OBJTYPE(QMGR)
    AUTHLIST(ALTUSR,CHG,CONNECT,DLT,DSP,INQ,SET)

我想将每条记录存储为散列数组中的散列。 这就是我目前的做法(请不要对我写这篇文章的方式持否定态度,可能有 100 种更好的方法可以做到这一点,但我仍在学习,所以请记住这一点,欢迎提出改进建议):

    my @authrecs;   
    my @authrecoutput;  #this array contains the text output as displayed above, each line in a different element. 
    
    my $len = @authrecoutput;
    for (my $i = 0; $i <= $len; $i++){
        if(@authrecoutput[$i] =~ /^AMQ8864I/)  #when the eventcode occurs i start creating a new hash and store all properties in it. 
        {
            my $rec = {};
            while (@authrecoutput[$i+1] =~ /(\S+)\((.+?)\)/g ){
                $rec->{$1} = $2;
            }
            while (@authrecoutput[$i+2] =~ /(\S+)\((.+?)\)/g ){ 
                $rec->{$1} = $2;
            }
            while (@authrecoutput[$i+3] =~ /(\S+)\((.+?)\)/g ){  #problem with this that now the script only looks at $i+3 lines so anything on $1+4 i will miss.  
                $rec->{$1} = $2;
            }
            push @authrecs, $rec; 
        }
    
    }

    print Dumper @authrecs;

我的输出:

$VAR1 = {
          'AUTHLIST' => 'BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT,PASSALL,PASSID,SET,SETALL,SETID',
          'ENTTYPE' => 'GROUP',
          'ENTITY' => 'GROUP1',
          'OBJTYPE' => 'QUEUE',
          'PROFILE' => 'SYSTEM.ADMIN.COMMAND.QUEUE'
        };
$VAR2 = {
          'PROFILE' => 'SYSTEM.MQEXPLORER.REPLY.MODEL',
          'ENTITY' => 'GROUP1',
          'OBJTYPE' => 'QUEUE',
          'ENTTYPE' => 'GROUP'
        };
$VAR3 = {
          'PROFILE' => 'self',
          'OBJTYPE' => 'QMGR',
          'ENTITY' => 'GROUP1',
          'ENTTYPE' => 'GROUP',
          'AUTHLIST' => 'ALTUSR,CHG,CONNECT,DLT,DSP,INQ,SET,SETALL,SETID,CTRL,SYSTEM'
        };

这可行,但问题是在数组中查找属性不是动态的,并且设置为@authrecoutput[$i+3] 的固定长度。例如,'SYSTEM.MQEXPLORER.REPLY.MODEL' 配置文件在文本输出中有 4 行,而包含 'AUTHLIST' 属性的第四行显然没有被捕获。

我尝试嵌套第二个 for 循环,当事件代码 AMQ8864I 再次发生时会中断(因为那是我知道正在显示新记录的时候)但我没有找到如何在正则表达式条件下中断 for 循环,如果那样的话甚至是一件事。

我怎样才能将其编码为更加动态并读取行,直到检测到下一次出现“AMQ8864I”。

【问题讨论】:

    标签: arrays perl for-loop dynamic hash


    【解决方案1】:

    我使用变量$inside 作为标志,告诉我我是否在记录中。如果是,我将元组存储到数组中的最后一个哈希中。当一个新的部分开始时,我将一个空散列推入数组。

    #!/usr/bin/perl
    use warnings;
    use strict;
    
    my @arr;
    my $inside;
    while (<DATA>) {
        $inside = 0 unless /^ {4}/;
    
        if ($inside) {
            $arr[-1]{$1} = $2 while / (\S+)\(([^)]+)\)/g;
        }
    
        if (/^ AMQ8864I:/) {
            $inside = 1;
            push @arr, {};
        }
    }
    use Data::Dumper;
    print Dumper \@arr;
    
    __DATA__
    ...
    

    输出:

    $VAR1 = [
              {
                'ENTTYPE' => 'GROUP',
                'AUTHLIST' => 'BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT',
                'OBJTYPE' => 'QUEUE',
                'PROFILE' => 'SYSTEM.ADMIN.COMMAND.QUEUE',
                'ENTITY' => 'GROUP1'
              },
              {
                'OBJTYPE' => 'QUEUE',
                'ENTITY' => 'GROUP1',
                'PROFILE' => 'SYSTEM.MQEXPLORER.REPLY.MODEL',
                'AUTHLIST' => 'BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT',
                'ENTTYPE' => 'GROUP'
              },
              {
                'ENTITY' => 'GROUP1',
                'OBJTYPE' => 'QMGR',
                'PROFILE' => 'self',
                'AUTHLIST' => 'ALTUSR,CHG,CONNECT,DLT,DSP,INQ,SET',
                'ENTTYPE' => 'GROUP'
              }
            ];
    

    【讨论】:

    • 嘿,感谢您提供的解决方案,非常有用,而且在编写简短有效的代码时,我似乎还有很多东西要学:) 我只是想知道生成的哈希数组是否重要现在结构不同了?首先是: $VAR1={key => value, key => value}; ^$VAR2={...., ....} 而现在一切都在 VAR1 上: $VAR1 = [ {....,.... }, {.....,...}{ .....}{.....} 这会改变访问单个键和值的方式吗?
    • 不,一样,我只是用Dumper \@arr而不是Dumper @arr。毕竟,这是一个单一的变量。
    【解决方案2】:

    匹配范围运算符的使用提供了解决方案的其他方法。

    use strict;
    use warnings;
    use feature 'say';
    
    use Data::Dumper;
    
    my $id = 'AMQ8864I';
    my(%data, $record);
    
    while( <DATA> ) {
        if( /^ $id:/ .. /^\s+AUTHLIST/ ) {
            unless( /^ $id:/ ) {
                $record->{$1} = $2 while /\s+(.+?)\((.*?)\)/g;
            } else {
                push @{$data{$id}}, $record if defined $record;
                $record = undef;
            }
        }
    }
    
    push @{$data{$id}}, $record if defined $record;
    
    say Dumper(\%data);
    
    __DATA__
         1 : DISPLAY AUTHREC GROUP('GROUP1')
     AMQ8864I: Display authority record details.
        PROFILE(SYSTEM.ADMIN.COMMAND.QUEUE)     ENTITY(GROUP1)
        ENTTYPE(GROUP)                          OBJTYPE(QUEUE)
        AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT)
     AMQ8864I: Display authority record details.
        PROFILE(SYSTEM.MQEXPLORER.REPLY.MODEL)
        ENTITY(GROUP1)                         ENTTYPE(GROUP)
        OBJTYPE(QUEUE)
        AUTHLIST(BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT)
     AMQ8864I: Display authority record details.
        PROFILE(self)                           ENTITY(GROUP1)
        ENTTYPE(GROUP)                          OBJTYPE(QMGR)
        AUTHLIST(ALTUSR,CHG,CONNECT,DLT,DSP,INQ,SET)
    

    输出

    $VAR1 = {
              'AMQ8864I' => [
                              {
                                'ENTTYPE' => 'GROUP',
                                'AUTHLIST' => 'BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT',
                                'OBJTYPE' => 'QUEUE',
                                'PROFILE' => 'SYSTEM.ADMIN.COMMAND.QUEUE',
                                'ENTITY' => 'GROUP1'
                              },
                              {
                                'ENTTYPE' => 'GROUP',
                                'ENTITY' => 'GROUP1',
                                'OBJTYPE' => 'QUEUE',
                                'PROFILE' => 'SYSTEM.MQEXPLORER.REPLY.MODEL',
                                'AUTHLIST' => 'BROWSE,CHG,CLR,DLT,DSP,GET,INQ,PUT'
                              },
                              {
                                'ENTTYPE' => 'GROUP',
                                'AUTHLIST' => 'ALTUSR,CHG,CONNECT,DLT,DSP,INQ,SET',
                                'OBJTYPE' => 'QMGR',
                                'PROFILE' => 'self',
                                'ENTITY' => 'GROUP1'
                              }
                            ]
            };
    

    【讨论】:

    • 嘿,感谢您提供此解决方案。我不知道范围运算符也适用于模式。唯一的缺点是我想重用此代码来存储来自不同 DISPLAY 命令的类似文本输出,因此数据不会总是以 AUTHLIST 属性结尾。有没有办法捕捉 AMQ8864I 事件之间的内容?我问的原因是因为 MQ 总是以相同的结构显示显示命令,但事件编号不同: AMQ8XXX ....record .... AMQ8XXX .... record .... AMQ8XXX ... record 。 ..AMQ8XXX.
    • 如果没有看到完整的输入数据样本,就不可能预测解决问题的最佳方法。模式可以调整为AMQ8\d{4}\w{1} 以匹配您提到的。范围运算符在匹配结束块 AUTHLIST 时触发。如果有任何其他数据,则需要对算法进行调整(原始帖子的所有块都以 AUTHLIST 结尾)。应该有一些指示块完成的指示符——对于某些它将是下一个 AMQ8XXXX 块的开始,但是最后一个块呢——如果完成了会表明什么?
    猜你喜欢
    • 2013-03-06
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2013-02-04
    • 2018-07-04
    • 2012-07-13
    相关资源
    最近更新 更多