blackadder has asked for the wisdom of the Perl Monks concerning the following question:

This is my data
interface mgmt0 ip address 10.33.81.52 255.255.240.0 interface fc1/1 switchport description Trunk switchport mode E channel-group 3 force no shutdown interface fc1/2 interface fc1/3 no shutdown interface fc1/4 no shutdown interface fc1/5 interface fc1/6 interface fc1/7 switchport description DMX02_FA4CA no shutdown interface fc1/8 no shutdown interface fc1/9 interface fc1/10 interface fc1/11 switchport description DMX02_FA7CA no shutdown interface fc1/12 no shutdown interface fc1/13 switchport mode SD switchport speed 1000 no shutdown interface fc1/14 interface fc1/15 no shutdown
I want capture :
interface mgmt0 = interface fc1/1 = switchport description Trunk interface fc1/2 = interface fc1/3 = interface fc1/4 = interface fc1/5 = interface fc1/6 = interface fc1/7 =switchport description DMX02_FA4CA . . . .
So I nicked this code
#! c:/perl/bin/prl.exe # use strict; my ($Rec,$pc_name); while (<DATA>) { $pc_name = $1, next if (/interface (\.)+$/); $Rec->{$pc_name}->{$1} = $2 if (/switchport description (\.+)$/); } for my $data (keys %{$Rec}) { print "$data \n"; for my $data2 (keys %{$Rec->{$data}}) { print "\t$data2 : $Rec->{$data}->{$data2}\n"; } }
Although the above code makes sense to me, but I didn't get any output!

I tinkered with the code for a while, but still to no avail. Therefore I am going to resort to your great wisdom, yet again.

Can a wise monk please enlighten me....Many Thanks



PS: I will learn this RegEx eventually!

Blackadder

Replies are listed 'Best First'.
Re: RegEx Blues
by Fletch (Bishop) on Sep 22, 2005 at 17:47 UTC

    You got nothing because (\.)+ matches one or more occurences of a single literal period. You mean /interface (.+)$/ instead.

      Ah,...I blame it on the migrain that I have been getting on almost daily basis.

      Perl Monks seems to be my only remedy at the moment.

      Blackadder
Re: RegEx Blues
by diotalevi (Canon) on Sep 22, 2005 at 17:54 UTC

    Try this out.

    use strict; use warnings; # See perlvar for why $/ = "" causes $record to contain your entire re +cord at once. The point is to read your data record-at-a-time instead + of line-at-a-time. local $/ = ""; while ( my $record = <DATA> ) { # See perlre for why (.+) fetches everything on the same line as t +he text being matched but doesn't continue onto the next line. Rememb +er, $record is a multi-line string. my ( $pc_name ) = $record =~ /interface (.+)/; my ( $switch_name ) = $record =~ /switchport description (.+)/; print "$pc_name: $switch_name\n"; }
      Yes, Local $/ has sorted most of my issues.

      Thanks
      Blackadder
Re: RegEx Blues
by ikegami (Patriarch) on Sep 22, 2005 at 17:59 UTC

    . means "any one character".
    \. means "one period".
    You keep using the wrong one.

    You used (XXX)+ where you mean (XXX+).

    Then there's using $2 when the regexp only has one capture.

    You didn't create any records for interfaces with no descriptions (but your desired output indicates you want this).

    $Recs is a more accurate name for $Rec.

    The XXX, XXX if XXX syntax is unusual and therefore harder to read.

    Recs has no reason for being a hash reference. A hash is sufficient.

    Your indenting is inconsistent. Pick a style and stick with it.

    use warnings was missing. It would have identified your problems here.

    use strict; use warnings; my %Recs; my $pc_name; while (<DATA>) { if (/interface (\S+)$/) { $pc_name = $1; $Recs{$pc_name} = {}; # Create record. next; } if (/switchport description (.*)$/) { $Recs{$pc_name}{description} = $1; next; } } for $pc_name (keys %Recs) { my $description = $Recs{$pc_name}{description}; if (defined $description) { $description = "switchport description $description"; } else { $description = ""; } print("interface $pc_name = switchport description $description\n" +); }
    or if you're not planning on capturing more than just the description:
    use strict; use warnings; my %descriptions; my $pc_name; while (<DATA>) { if (/interface (\S+)$/) { $pc_name = $1; $descriptions{$pc_name} = undef; next; } if (/switchport description (.*)$/) { $descriptions{$pc_name} = $1; next; } } for $pc_name (keys %descriptions) { my $description = $descriptions{$pc_name}; if (defined $description) { $description = "switchport description $description"; } else { $description = ""; } print("interface $pc_name = switchport description $description\n" +); }

    Update: Added missing paren.

    Update: Added creation of records with no description.

Re: RegEx Blues
by radiantmatrix (Parson) on Sep 22, 2005 at 19:12 UTC

    Hm, well...

    If you just want to print these values out:

    while (<DATA>) { chomp; print "\n$1 =" and next if /^(interface\s.+)/; print "$1" and next if /^\s+(switchport description\s.+)/; }

    If getting them into a hash is the point:

    my (%data, $last); while (<DATA>) { #~ print STDERR $_; chomp; if (/^(interface\s.+)/) { $last = $1; $data{$last} = ''; next; } $data{$last}=$1 and next if /^\s+(switchport description\s.+)/; } ##now print for ( sort keys %data ) { print "$_ = $data{$_}\n" }

    The main problems you're having are illuminated in the posts above, so I won't belabor them. Just read perlre and perlretut again, and maybe pick up a copy of Mastering Regular Expressions (ISBN 0596002890).

    <-radiant.matrix->
    Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law
Re: RegEx Blues
by Hue-Bond (Priest) on Sep 22, 2005 at 18:11 UTC
    my ($Rec,$pc_name); while (<DATA>) { $pc_name = $1, next if (/^(interface .+)$/); $Rec->{$pc_name} ||= undef; ## let it exist $Rec->{$pc_name} = $1 if (/^\s+(switchport description .+)$/); } for (sort keys %{$Rec}) { my $val = $Rec->{$_} ? $Rec->{$_} : ""; print "$_ = $val\n"; } __OUTPUT__ interface fc1/1 = switchport description Trunk interface fc1/10 = interface fc1/11 = switchport description DMX02_FA7CA interface fc1/12 = interface fc1/13 = interface fc1/14 = interface fc1/15 = interface fc1/2 = interface fc1/3 = interface fc1/4 = interface fc1/5 = interface fc1/6 = interface fc1/7 = switchport description DMX02_FA4CA interface fc1/8 = interface fc1/9 = interface mgmt0 =

    This is ok if you don't mind the different order of the output lines.

    --
    David Serrano