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

mwecs4sa  于 8个月前  发布在  Perl
关注(0)|答案(4)|浏览(101)

我正在尝试设计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";  
  }  
}

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

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来捕获最后一种情况。
有没有人能就如何使这一工作或另一种方法提供任何想法/建议?

jum4pzuy

jum4pzuy1#

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

li9yvcax2#

我想尝试使用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
0qx6xfy6

0qx6xfy63#

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或更高版本;我从Can I use Perl regular expressions to match balanced text得到这个?

sqserrrh

sqserrrh4#

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

相关问题