【问题标题】:How can I parse runmqsc command output using Perl?如何使用 Perl 解析 runmqsc 命令输出?
【发布时间】:2009-08-26 19:35:51
【问题描述】:

我正在尝试设计 Perl 正则表达式来解析 IBM 的 runmqsc 实用程序的命令输出。

每一行感兴趣的输出都包含一个或多个属性/值对,格式为:“ATTRIBUTE(VALUE)”。属性的值可以为空,也可以包含括号本身。通常,在给定的行上最多出现两个属性/值对,因此正则表达式是在此假设下编写的。

Perl RE 的示例输入:

CHANNEL(TO.IPTWX01)                     CHLTYPE(CLUSRCVR)  
DISCINT(6000)                           SHORTRTY(10)  
TRPTYPE(TCP)                            DESCR( )  
LONGTMR(1200)                           SCYEXIT( )  
CONNAME(NODE(1414))                     MREXIT( )  
MREXIT( )                               CONNAME2(SOME(1416))  
TPNAME( )                               BATCHSZ(50)  
MCANAME( )                              MODENAME( )  
ALTTIME(00.41.56)                       SSLPEER()  
CONTRIVED()                             ATTR (00-41-56)   
CONTRIVED()                             DOCTORED()  
MSGEXIT( )   

我有以下 Perl 代码来捕获每个属性/值对。

Perl 代码

my $resplit = qr/\s+([^\s]+(?:\([^)]*\))?)\s?/;  
while ( <IN2> )  
{ s/[\s\r\n]+$//;  
  if ( m/^\s(?:$resplit)(?:$resplit)?$/ )  
  { my ($one,$two) = ($1,$2);  
    print "one: $one, two: $two\n";  
  }  
} 

以下是将上述代码应用于示例输入时的输出:

一:CHANNEL(TO.IPTWX01),二:CHLTYPE(CLUSRCVR) 一:DISCINT(6000),二:SHORTY(10) 一:TRPTYPE(TCP),二:DESCR() 一:LONGTMR(1200),二:SCYEXIT() 一:CONNAME(NODE(1414)),二:MREXIT() 一:MREXIT( ),二:CONNAME2(SOME(1416)) 一:TPNAME( ),二:BATCHSZ(50) 一:MCANAME(),二:MODENAME() 一:ALTTIME(00.41.56),二:SSLPEER() 一:CONTRIVED(),二:ATTR(00-41-56) 一:做作(),二:医生() 一:MSGEXIT(,二:)

这很好用,除了输出中的最后一行 多于。我真的很难弄清楚如何 修改上面的表达式 $resplit 以捕获最后一种情况。

任何人都可以就如何使这项工作提供任何想法/建议或 另一种方法?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    Text::Balanced 模块旨在处理此类问题。这种方法也可以处理任意数量的列。

    use strict;
    use warnings;
    use Text::Balanced qw(extract_bracketed);
    
    my ($extracted, $remainder, $prefix);
    while ( defined($remainder = <DATA>) ){
        while ( Get_paren_text() ){
            $prefix =~ s/ //g;
            print $prefix, $extracted, "\n";
        }
    }
    sub Get_paren_text {
        ($extracted, $remainder, $prefix) 
            = extract_bracketed($remainder, '()', '[\w ]+');
        return defined $extracted;
    }
    
    __DATA__
    CHANNEL(TO.IPTWX01)  CHLTYPE(CLUSRCVR)      FOO( ( BAR) )
    DISCINT(6000)        SHORTRTY(10)           BIZZ((((BUZZ) ) ) ) )
    TRPTYPE(TCP)         DESCR( )               
    LONGTMR(1200)        SCYEXIT( )             
    CONNAME(NODE(1414))  MREXIT( )              
    MREXIT( )            CONNAME2(SOME(1416))   
    TPNAME( )            BATCHSZ(50)            
    MCANAME( )           MODENAME( )            
    ALTTIME(00.41.56)    SSLPEER()              
    CONTRIVED()          ATTR (00-41-56)        
    CONTRIVED()          DOCTORED()             
    MSGEXIT( )
    

    【讨论】:

      【解决方案2】:

      我想尝试使用Regexp::Grammars

      原来是这样:

      #! /opt/perl/bin/perl
      use strict;
      #use warnings;
      use 5.10.1;
      
      use Regexp::Grammars;
      
      my $grammar = qr{
        <line>
      
        <token: line>
          (?: <[pair]> \s* )+
      
          (?{
            my $arr = $MATCH{pair};
            local $MATCH = {};
      
            for my $pair( @$arr ){
              my($key)   = keys   %$pair;
              my($value) = values %$pair;
              $MATCH->{$key} = $value;
            }
          })
      
        <token: pair>
          <attrib> \s* \( \s* <value> \s* \)
          (?{
            $MATCH = {
              $MATCH{attrib} => $MATCH{value}
            };
          })
      
        <token: attrib>
          [^()]*?
      
        <token: value>
          (?:
            <MATCH=pair> |
            [^()]*?
          )
      }x;
      
      use warnings;
      
      my %attr;
      while( my $line = <> ){
        $line =~ /$grammar/;
        for my $key ( keys %{ $/{line} } ){
          $attr{$key} = $/{line}{$key};
        }
      }
      
      use YAML;
      
      say Dump \%attr;
      
      --- 海拔时间:00.41.56 ATTR: 00-41-56 批次:50 频道:TO.IPTWX01 CHLTYPE:CLUSRCVR 名称: 节点:1414 CONNAME2: 一些:1416 设计:'' 描述:'' 区别:6000 医生:'' 龙头:1200 MCANAME: '' 模式名:'' 出口:'' 消息退出:'' SCYEXIT:'' 短:10 SSL 同行:'' TPNAME:'' TRPTYPE:TCP

      【讨论】:

        【解决方案3】:
        while ( <IN2> ) {
            while ( /([A-Z]+)\s*(\((?:[^()]*+|(?2))*\))/g ) {
                print "$1$2\n";
            }
        }
        

        这适用于嵌套的括号,例如

        CONNAME(NODE(1414, SOME(1416) ) )           ATTR (00-41-56)
        

        (?2) 部分是递归的,*+ 表示“不要回溯” - 仅适用于 Perl 5.10 或更高版本;我是从http://faq.perl.org/perlfaq6.html#Can_I_use_Perl_regul得到这个的

        【讨论】:

          【解决方案4】:
          #!/usr/bin/perl
          
          use strict;
          use warnings;
          
          my @parsed;
          
          while ( my $line = <DATA> ) {
              while ( $line =~ / ([A-Z0-9]+) \s* \( (.*?) \) \s /gx ) {
                  push @parsed, { $1 => $2 }
              }
          }
          
          use Data::Dumper;
          print Dumper \@parsed;
          
          __DATA__
          CHANNEL(TO.IPTWX01)                     CHLTYPE(CLUSRCVR)
          DISCINT(6000)                           SHORTRTY(10)
          TRPTYPE(TCP)                            DESCR( )
          LONGTMR(1200)                           SCYEXIT( )
          CONNAME(NODE(1414))                     MREXIT( )
          MREXIT( )                               CONNAME2(SOME(1416))
          TPNAME( )                               BATCHSZ(50)
          MCANAME( )                              MODENAME( )
          ALTTIME(00.41.56)                       SSLPEER()
          CONTRIVED()                             ATTR (00-41-56)
          CONTRIVED()                             DOCTORED()
          MSGEXIT( )
          

          【讨论】:

          • 相当不错,但对于“CONNAME(NODE(1414))”而不是“CONNAME(NODE(1414))”失败。不过,也许这不是一个可能的输入。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-25
          • 2014-01-14
          相关资源
          最近更新 更多