Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl regex multi-line match into hash

Tags:

regex

hash

perl

I'm successfully parsing a cisco config file, and grabbing the sections of config between each marker (cisco uses the ! symbol) using a multi line regex of:

/(search string)/i .. /^!/ 

My code looks like:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my (@results, @data) ;

#Test data to simulate a while loop on a file-handle running through a config file.
@data =  (
    "vlan 81" ,
    " name Vlan 81 test1" ,
    "!" ,
    "vlan 82" ,
    " name Vlan 82 test2" ,
    "!" ,
    "vlan 83" ,
    " name Vlan 83 test3" ,
    "!"
);

foreach ( @data ) {
    if ( /vlan/i .. /^!/ ) {
         push  (@results , $_) ;                
    }
}

print Dumper ( @results ) . "\n" ;

exit;

It works really well, but I want to push the results into a hash, with each section of code being an anonymous array, so the results would look something like:

%Vlan -> [Vlan 81, name Vlan 81 test1] , [Vlan 82, name Vlan 82 test2] , [Vlan 83, name Vlan 83 test3]

But I can't work out how to do it, my code matches per line between the search string and the marker and I just end up rebuilding the results into another array, line by line.

Any help is much appreciated.

Cheers,

Andy

like image 235
user1039417 Avatar asked Dec 28 '22 03:12

user1039417


1 Answers

I'm not sure what you mean about a hash, as the contents you describe are just a list of anonymous arrays. There are no keys so you can only produce an array. If you can explain which part of the data is to be the key then we can go for a hash.

The use warnings pragma is preferable to the -w shebang modifier as it is more flexible and can be negated.

The range operator .. may be cute but you mustn't squeeze it into use wherever possible.

Setting the input separator to "!\n" will allow you to read in all related lines at once, which can then be pushed onto your array.

The code looks like this

use strict;
use warnings;

use Data::Dumper;

my @Vlan;

$/ = "!\n";

while  (<DATA>) {
  chomp;
  push @Vlan, [split /[\r\n]+/];
}

print Data::Dumper->Dump([\@Vlan], ['*Vlan']);

__DATA__
vlan 81
name Vlan 81 test1
!
vlan 82
name Vlan 82 test2
!
vlan 83
name Vlan 83 test3
!

output

@Vlan = (
          [
            'vlan 81',
            'name Vlan 81 test1'
          ],
          [
            'vlan 82',
            'name Vlan 82 test2'
          ],
          [
            'vlan 83',
            'name Vlan 83 test3'
          ]
        );

EDIT

If the key of the hash is always the first line of the record set, then this program produces a hash as you requested

use strict;
use warnings;

use Data::Dumper;

my %Vlan;

$/ = "!\n";

while  (<DATA>) {
  chomp;
  my ($k, $v) = split /[\r\n]+/;
  $Vlan{$k} = $v;
}

print Data::Dumper->Dump([\%Vlan], ['*Vlan']);

__DATA__
vlan 81
name Vlan 81 test1
!
vlan 82
name Vlan 82 test2
!
vlan 83
name Vlan 83 test3
!

output

%Vlan = (
          'vlan 81' => 'name Vlan 81 test1',
          'vlan 83' => 'name Vlan 83 test3',
          'vlan 82' => 'name Vlan 82 test2'
        );
like image 187
Borodin Avatar answered Jan 09 '23 05:01

Borodin