Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

matching certain lines

5 views
Skip to first unread message

Chris Stinemetz

unread,
Feb 9, 2013, 12:06:46 PM2/9/13
to begi...@perl.org
I would like to only work with the data that has a line with |68| in it
print that line and then print each subsequent lines in that match
/\|7\|\d+\|\d+/ until #END is reached and then repeat for the rest of the
input data.

Below is what I have attempted.

Thanks in advance.

Chris


#!/usr/bin/perl

use warnings;
use strict;

my ( $col1, $col2, $col3 );

while( my $line = <DATA> ) {
chomp($line);
if ( $line =~ /(.*\|68\|.*)/ ) {
my $OM = $1;
print $OM, "\n";
}
if ( $line =~ /(\|\d)\|(\d+)\|(\d+)/ ) {
$col1 = $1;
$col2 = $2;
$col3 = $3;
print join("\t", $col1, $col2, $col3 ), "\n";
}
}


__DATA__
#LOGNUM|68|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.3:DSFPVCARD.6
|5883.2.0.330.1.1|5883.2.0.330.1.1|0x3|19|1|1
|ACP3|8
|7|1|9
|7|2|436
|7|3|5
|7|4|0
|7|5|0
|7|6|0
|7|7|0
|7|8|0
#END


#LOGNUM|69|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.3:DSFPVCARD.6
|5883.2.0.330.1.1|5883.2.0.330.1.1|0x3|26|1|1
|ACP3|19
|7|1|0
|7|2|0
|7|3|0
|7|4|0
|7|5|0
|7|6|0
|7|7|0
|7|8|0
|7|9|0
|7|10|20
|7|11|0
|7|12|0
|7|13|0
|7|14|0
|7|15|0
|7|16|0
|7|17|0
|7|18|0
|7|19|0
#END


#LOGNUM|70|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.3:DSFPVCARD.6
|5883.2.0.330.1.1|5883.2.0.330.1.1|0x3|68|1|1
|ACP3|12
|7|1|0
|7|2|2610
|7|3|0
|7|4|0
|7|5|2575
|7|6|0
|7|7|0
|7|8|0
|7|9|0
|7|10|0
|7|11|0
|7|12|0
#END

David Precious

unread,
Feb 9, 2013, 12:49:23 PM2/9/13
to begi...@perl.org
On Sat, 9 Feb 2013 11:06:46 -0600
Chris Stinemetz <chrisst...@gmail.com> wrote:

> I would like to only work with the data that has a line with |68| in
> it print that line and then print each subsequent lines in that match
> /\|7\|\d+\|\d+/ until #END is reached and then repeat for the rest of
> the input data.

OTTOMH,

perl -lne '/\|68\|/ .. /\#END/ && /\|7\|\d+\|\d+/ && print'

For an explanation, look up ".." in perldoc perlop - the flip-flop
operator - it evaluates to true once the first condition (in this case,
the current line matches the regex /\|68\|/ becomes true), and
continues to evaluate to a true value until the second condition is true
(in this case, the current line contains "#END"), at which point it goes
back to false again. Combining that with a check for the line
containing what you want gets you most of the way there; I think it'll
skip the start & end lines though, so you'll probably want to modify
the last regex to include them.



--
David Precious ("bigpresh") <dav...@preshweb.co.uk>
http://www.preshweb.co.uk/ www.preshweb.co.uk/twitter
www.preshweb.co.uk/linkedin www.preshweb.co.uk/facebook
www.preshweb.co.uk/cpan www.preshweb.co.uk/github


John W. Krahn

unread,
Feb 9, 2013, 3:59:24 PM2/9/13
to Perl Beginners
Chris Stinemetz wrote:
>
> I would like to only work with the data that has a line with |68| in it
> print that line and then print each subsequent lines in that match
> /\|7\|\d+\|\d+/ until #END is reached and then repeat for the rest of the
> input data.
>
> Below is what I have attempted.
>
> Thanks in advance.
>
> Chris
>
>
> #!/usr/bin/perl
>
> use warnings;
> use strict;
>
> my ( $col1, $col2, $col3 );
>
> while( my $line =<DATA> ) {
> chomp($line);
> if ( $line =~ /(.*\|68\|.*)/ ) {
> my $OM = $1;
> print $OM, "\n";
> }
> if ( $line =~ /(\|\d)\|(\d+)\|(\d+)/ ) {
> $col1 = $1;
> $col2 = $2;
> $col3 = $3;
> print join("\t", $col1, $col2, $col3 ), "\n";
> }
> }

Let's re-factor that down to its essence:

while ( <DATA> ) {
print if /\|68\|/;
print "$1\t$2\t$3\n" if /(\|\d)\|(\d+)\|(\d+)/;
}

Now we need to add something that starts at |68| and stops at #END:

while ( <DATA> ) {
if ( /\|68\|/ .. /^#END/ ) {
print if /\|68\|/;
print "$1\t$2\t$3\n" if /(\|\d)\|(\d+)\|(\d+)/;
}
}



John
--
Any intelligent fool can make things bigger and
more complex... It takes a touch of genius -
and a lot of courage to move in the opposite
direction. -- Albert Einstein

timothy adigun

unread,
Feb 9, 2013, 4:27:41 PM2/9/13
to Chris Stinemetz, Perl Beginners
Hi,
On Sat, Feb 9, 2013 at 6:06 PM, Chris Stinemetz <chrisst...@gmail.com>wrote:

> I would like to only work with the data that has a line with |68| in it
>

Does it mean even, that |68| can be anyway in the your data before any of
the #END is reached?
If yes, then I think you have been given a good solution. If not, you might
want to see how to make *the* |68| you want different from any other ones
that might occur in your data.

Like you have this:
#LOGNUM|68|OPERATIONAL ....
....
...
#END

then somewhere else you have this:
|5883.2.0.330.1.1|5883.2.0.330.1.1|0x3|68|1|1
....
....
#END
--
Tim

Uri Guttman

unread,
Feb 9, 2013, 6:15:59 PM2/9/13
to begi...@perl.org
On 02/09/2013 03:59 PM, John W. Krahn wrote:

>
> Let's re-factor that down to its essence:
>
> while ( <DATA> ) {
> print if /\|68\|/;
> print "$1\t$2\t$3\n" if /(\|\d)\|(\d+)\|(\d+)/;
> }
>
> Now we need to add something that starts at |68| and stops at #END:
>
> while ( <DATA> ) {
> if ( /\|68\|/ .. /^#END/ ) {
> print if /\|68\|/;
> print "$1\t$2\t$3\n" if /(\|\d)\|(\d+)\|(\d+)/;
> }
> }

there is a great feature with the .. flip/flop op that isn't well known.
it returns not just a boolean state but a count of where it is in the
range. so you can use that value to handle the first line differently
and not need to copy the regex which can lead to a bug if it changes and
you forget to edit both copies:

if ( my $range = /\|68\|/ .. /^#END/ ) {
print if $range == 1 ;

the last line in the range gets a number with E0 appended so it is the
same value but you can check for the /E/ and do something there:

print "DONE\n" if $range =~ /E/ ;

uri


Chris Stinemetz

unread,
Feb 10, 2013, 7:51:20 AM2/10/13
to Uri Guttman, begi...@perl.org
Thank you everyone for you help.

-Chris
> --
> To unsubscribe, e-mail: beginners-...@perl.org
> For additional commands, e-mail: beginne...@perl.org
> http://learn.perl.org/
>
>
>

Chris Stinemetz

unread,
Feb 10, 2013, 9:05:36 AM2/10/13
to Uri Guttman, begi...@perl.org
To take this a step further.

How would you go about creating a hash to sum up all the values in group $3
utilizing the flip/flop operator and print the results of the key and value
with the key being group $2?

Thank you,

Chris

while( <DATA> ) {
if ( /0x3\|68\|/ .. /^#END/ ) {
print if /\|68\|/;
print join(",", $1, $2, $3 ), "\n" if /\|(\d)\|(\d+)\|(\d+)/;
}
}

__DATA__
#LOGNUM|110|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.4:DSFPVCARD.5
|6261.2.0.330.1.1|6261.2.0.330.1.1|0x3|68|1|1
|ACP2|12
|7|1|0
|7|2|2636
|7|3|0
|7|4|0
|7|5|2601
|7|6|0
|7|7|0
|7|8|0
|7|9|0
|7|10|0
|7|11|0
|7|12|0
#END


#LOGNUM|134|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.4:DSFPVCARD.5
|6261.2.0.330.1.1|6261.2.0.330.1.1|0x3|68|1|1
|ACP5|12
|7|1|0
|7|2|2638
|7|3|0
|7|4|0
|7|5|2592
|7|6|0
|7|7|0
|7|8|0
|7|9|0
|7|10|0
|7|11|0
|7|12|0
#END


#LOGNUM|150|OPERATIONAL
|NETWORK.1:SUBNETWORK.100:EBSC.1:EBSCSHELF.4:DSFPVCARD.7
|6263.2.0.330.1.1|6263.2.0.330.1.1|0x3|68|1|1
|ACP1|12
|7|1|0
|7|2|2573
|7|3|0
|7|4|0
|7|5|2551

Chris Stinemetz

unread,
Feb 10, 2013, 5:00:22 PM2/10/13
to Uri Guttman, begi...@perl.org
On Sun, Feb 10, 2013 at 8:05 AM, Chris Stinemetz
<chrisst...@gmail.com>wrote:

> To take this a step further.
>
> How would you go about creating a hash to sum up all the values in group
> $3 utilizing the flip/flop operator and print the results of the key and
> value with the key being group $2?
>
>
This is what I came up with and seems to do the trick. Hopefully it can
help someone else.

my %hash;
while (<DATA>) {
if ( /0x3\|68\|/ .. /^#END/ ) {
if (/\|(\d)\|(\d+)\|(\d+)/) {
my @cols = ( $1, $2, $3 );
$hash{ $cols[1] }{instance}++;
$hash{ $cols[1] }{volume} += $cols[2];
}
}
}


## header
print join(",", qw( Peg Instance Subtotal )), "\n";

foreach ( sort { $a <=> $b } keys(%hash) ) {
print join( ",", $_, $hash{$_}{instance}, $hash{$_}{volume} ), "\n";
}
0 new messages