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

Hi, I'm not sure if my title is very accurate for what I'm trying to achieve but I couldn't think of a better way to articulate it.

I have with route information that I want to split into an array with each element contain one route entry. However some route entries are multiline.

For Example:

C AAA.BBB.CCC.DDD 255.255.255.224 is directly connected, INTERFACENAME

O E1 WWW.XXX.YYY.ZZZ 255.255.224.0

110/112 via AAA.BBB.DDD.EEE, 696:56:46, INTERFACENAME

I would like to split into....

VAR1 = 'C AAA.BBB.CCC.DDD 255.255.255.224 is directly connected, INTERFACENAME'

VAR2 = 'O E1 WWW.XXX.YYY.ZZZ 255.255.224.0

110/112 via AAA.BBB.DDD.EEE, 696:56:46, INTERFACENAME'

I was thinking maybe I could split on '\n' and then join certain elements if they match the 'VAR2' format like above? Or can someone think of a better way?

Many thanks

  • Comment on Trying to split a file into array conditionally

Replies are listed 'Best First'.
Re: Trying to split a file into array conditionally
by bart (Canon) on Nov 15, 2011 at 12:04 UTC
    Perhaps you could only split where the next line doesn't start with an opening square bracket?

    split takes a regex, thus this is fairly easy.

    @info = split /\n(?!\[)/, $filecontents;
      Thanks guys...... I've gone with brats solution.... it does the trick nicely! cheers! :)
Re: Trying to split a file into array conditionally
by JavaFan (Canon) on Nov 15, 2011 at 12:10 UTC
    It's hard to give a general case for just two examples. Anything anyone suggest may break on your third line. Given the two examples, I wouldn't split - I'd just match what I want. Perhaps something like (untested):
    my @what_i_want = $what_i_have =~ /(\S.*?INTERFACENAME)/gs;
Re: Trying to split a file into array conditionally
by pvaldes (Chaplain) on Nov 15, 2011 at 12:14 UTC
    You could also split all by INTERFACENAME and then print each value followed by the string "INTERFACENAME"
Re: Trying to split a file into array conditionally
by Marshall (Canon) on Nov 15, 2011 at 15:53 UTC
    From your question, it appears to me that you want to solve the "make all entries single strings" problem. I would key on the phrase "directly connected", that is already a single line record. The two line records don't have that phrase in the first line and have "via" in the second line.

    So, the places below where there is a "push", the route record is "complete" meaning there is now a single string routing record.

    What you want to do past that is unclear to me. Perhaps you could explain further what info you want to extract now that you can get these records into single string entries.

    #!/usr/bin/perl -w use strict; my @routes; my $temp=''; while(<DATA>) { next if /^\s*$/; #skip blank lines chomp; if (/directly connected/) { push @routes, $_; next; } if (/via/) { push @routes, "$temp$_"; $temp=''; next; } $temp .= $_; } print join("\n",@routes),"\n"; __DATA__ C AAA.BBB.CCC.DDD 255.255.255.224 is directly connected, INTERFACENAME O E1 WWW.XXX.YYY.ZZZ 255.255.224.0 110/112 via AAA.BBB.DDD.EEE, 696:56:46, INTERFACENAME
Re: Trying to split a file into array conditionally
by ww (Archbishop) on Nov 15, 2011 at 18:37 UTC

    /me is with hbm on "INTERFACENAME." The logic of the question, it seems to me, requires that "INTERFACENAME" be OP's standin for variable text. And on that interpretation, bart's answer is elegant after one coerces the data into a single string. ++

    So, TIMTOWTDI. I've assumed variable text (and that the variable text ends with an uppercase alpha, [A-Z] character).

    #!/usr/bin/perl use Modern::Perl; # 938143 my $cachedline=""; my $multiline=""; my (@data, $line, @array_of_routeinfo); my $re = qr/directly connected, /; while ( <DATA> ) { # slurp __DATA__ push @data,$_ ; } for $line(@data) { chomp $line; $line =~ s/ $//g; # clean up data; one of mine had trailing s +paces if ($line eq '') { say "No more data"; exit(1); } if ( ($line =~ /$re/ && $cachedline eq "") ) { push @array_of_routeinfo, $line; } elsif ( ($line !~ /$re/) && ($line =~ /\d$/) ) { # if $line do +esn't contain "directly connected, " and ends with number $cachedline= $line; } elsif ( ($line !~ /re/ && $cachedline ne "") ) { # no "directly + connected, " AND $cachedline has content $multiline = "\t $cachedline"; $multiline .= "\n\t $line"; push @array_of_routeinfo, $multiline; $cachedline = ""; } } for (@array_of_routeinfo) { say; } say "Done"; __DATA__ C AAA.BBB.CCC.DDD 255.255.255.224 is directly connected, FOO O E1 WWW.XXX.YYY.ZZZ 255.255.224.0 [110/112] via AAA.BBB.DDD.EEE, 696:56:46, BAR B 111.222.333.444 255.255.255.0 [914/212] via 111.222.333.444, 345:59:03, BAZ X EEE.FFF.GGG.HHH 255.255.255.123 is directly connected, BAT 3 L1 OOO.PPP.QQQ.RRR 255.255.111.77 [A10/304/0xDFEE] via 444.333.222.000, 504:27:88, BLIVITZ

    Output is:

    C AAA.BBB.CCC.DDD 255.255.255.224 is directly connected, FOO O E1 WWW.XXX.YYY.ZZZ 255.255.224.0 [110/112] via AAA.BBB.DDD.EEE, 696:56:46, BAR B 111.222.333.444 255.255.255.0 [914/212] via 111.222.333.444, 345:59:03, BAZ X EEE.FFF.GGG.HHH 255.255.255.123 is directly connected, BAT 3 L1 OOO.PPP.QQQ.RRR 255.255.111.77 [A10/304/0xDFEE] via 444.333.222.000, 504:27:88, BLIVITZ Done
Re: Trying to split a file into array conditionally
by hbm (Hermit) on Nov 15, 2011 at 13:23 UTC

    I'm going to guess that 'INTERFACENAME' isn't actually static text... So maybe bart's solution, if it holds across all your data.