簡體   English   中英

如何使用Perl解析runmqsc命令輸出?

[英]How can I parse runmqsc command output using Perl?

我正在嘗試設計Perl regex來解析來自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";  
  }  
} 

以上代碼應用於示例輸入時的輸出:

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

除了上面輸出中的最后一行之外,這種方法很有用。 我真的很難弄清楚如何修改上面的表達式$ resplit來捕獲最后一種情況。

任何人都可以提供有關如何使這項工作或其他方法的任何想法/建議?

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( )

我想嘗試使用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;
---
ALTTIME: 00.41.56
ATTR: 00-41-56
BATCHSZ: 50
CHANNEL: TO.IPTWX01
CHLTYPE: CLUSRCVR
CONNAME:
  NODE: 1414
CONNAME2:
  SOME: 1416
CONTRIVED: ''
DESCR: ''
DISCINT: 6000
DOCTORED: ''
LONGTMR: 1200
MCANAME: ''
MODENAME: ''
MREXIT: ''
MSGEXIT: ''
SCYEXIT: ''
SHORTRTY: 10
SSLPEER: ''
TPNAME: ''
TRPTYPE: TCP
while ( <IN2> ) {
    while ( /([A-Z]+)\s*(\((?:[^()]*+|(?2))*\))/g ) {
        print "$1$2\n";
    }
}

這適用於嵌套的parens,例如

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

(?2)部分是遞歸的,* +表示“不回溯” - 僅適用於Perl 5.10或更高版本; 我從http://faq.perl.org/perlfaq6.html#Can_I_use_Perl_regul得到了這個

#!/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( )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM