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

I have a data list that gives me coordinates,
but I only want coordinates from specific key words Example:

A red line is found
at location 2.5 4.5
A Blue line is found
at location 2.6 4.5
A red line is found
at location 2.67 4.56
The red arc is found
at location 2.5 4.5

The only data I would want,
is about the "red line".
I was thinking of using the below script,
but I need to look for a key word "red line"
and have it read the line below that line to
get the locations.

Any suggestions?
#!usr/bin/perl use strict; open FILE, "<$ARGV[0]"; # $ARGV[0] is the file name # to pass in in the command line. my $i=1; while (<FILE>) { if ($i >2) { last;} print $_ ; $i++; } close FILE;

Replies are listed 'Best First'.
Re: Extracting Data from a second line
by Roy Johnson (Monsignor) on Feb 16, 2006 at 16:03 UTC
    This will print the red line line and the one following:
    while (<DATA>) { print if /red line/..././; } __DATA__ A red line is found at location 2.5 4.5 A Blue line is found at location 2.6 4.5 A red line is found at location 2.67 4.56 The red arc is found at location 2.5 4.5
    and if you don't want the red line line, make it
    print if (/red line/..././) =~ /E/;

    Caution: Contents may have been coded under pressure.
Re: Extracting Data from a second line
by brian_d_foy (Abbot) on Feb 16, 2006 at 19:15 UTC

    In these situations, I come up with a way to read one "record" at a time. You can do several things to get back all of the information for one record with one operation.

    For instance, write a function to read two lines at once (adding appropriate checks I don't cover here).

    while( defined( my $record = get_record( $fh ) ) { # ... } sub get_record { my $fh = shift; join '', scalar <$fh>, scalar <$fh>; }

    Sometimes preprocessing the data works better. You take your data file and join the appropriate lines. It's even better if you can track down the guy who can change the output at the source. :) Once it's all on one line, life is easy.

    A red line is found at location 2.5 4.5

    I've also found alternate delimiters useful. If you have to have a newline between the two interesting lines, maybe you can have a form feed (or something else) as the separator between records. Then you can set $/ to the record separator and read records instead of lines.

    A little database is a little more fancy than that, and more useful if you have to use the same data file over and over. Process the file once and store it in something such as a DBM::Deep file. Now lookups are as easy as using a hash, and you only have to process the file once.

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
Re: Extracting Data from a second line
by duff (Parson) on Feb 16, 2006 at 15:49 UTC
    my ($x,$y,$redline); while (<FILE>) { if ($redline) { ($x,$y) = /at location (\S+) (\S+)/; print "$x $y\n"; } $redline = /red line/; }

    Vary the details as needed. $redline is set to a true value when ever the pattern matches (and a false value when it doesn't match) so that on the next iteration of the loop, you'll be able to capture the location information.

Re: Extracting Data from a second line
by tweetiepooh (Hermit) on Feb 16, 2006 at 15:54 UTC
    My solution is different again. No error checking etc. Assumes all data as given.
    open(FH,"file"); while( <FH> ) { if (/red line/) { process(<FH>); } }
    Note this will read the lines below other 'keys' but will just pass them by.

    Not the most elegant or efficient but it does work.

      while( <FH> ) { if (/red line/) { process(<FH>); } }

      This doesn't work as required. Replace

          process(<FH>);

      with

          process(scalar <FH>);
Re: Extracting Data from a second line
by kwaping (Priest) on Feb 16, 2006 at 15:42 UTC
    Here's another way.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper::Simple; read DATA, my $text, 163; #<- manually grabbed size of DATA just for t +his example my @matches = ($text =~ /red line.*?location\s+(\d+\.\d+\s+\d+\.\d+)/s +g); print Dumper(@matches); __DATA__ A red line is found at location 2.5 4.5 A Blue line is found at location 2.6 4.5 A red line is found at location 2.67 4.56 The red arc is found at location 2.5 4.5
      Replace 163 with -s DATA.
        If I'm working with a regular filehandle, I always use -s to get the length to read, but unfortunately that doesn't work here. -s DATA will give you the length of the entire file, Perl code included, not just the part after __DATA__.

        Update: With that stated, I do realize it wouldn't hurt anything to supply a bigger number than required as the third argument to read.
Re: Extracting Data from a second line
by davidrw (Prior) on Feb 16, 2006 at 15:47 UTC
    and yet another approach ...
    while(<FILE>){ next unless /^(?:A|The) (.*) is found$/; my $item = $1; my $next_line = <FILE>; next unless $next_line =~ /^at location (.*)/; my $location = $1; # needs chomp'ing?? printf "'%s' is as [%s]\n", $item, $location; # or shove into some + data structure }
Re: Extracting Data from a second line
by ikegami (Patriarch) on Feb 16, 2006 at 15:36 UTC

    You need next, not last, and the modulus operator (%):

    my $i = 0; while (<FILE>) { next if ++$i % 2; print; }

    Here, $i can be replaced with $.:

    while (<FILE>) { next if $. % 2; print; }

    Or use next with a toggle:

    my $toggle = 0; while (<FILE>) { next if $toggle ^= 1; print; }

    By the way,
     #!usr/bin/perl
    is wrong. You must remove the leading space, and you must make the path absolute (or else it will only work form the root):
    #!/usr/bin/perl

    Update: I didn't read your post close enough. The above didn't answer your question. A solution would be:

    for (;;) { last if not defined (my $line1 = <FILE>); last if not defined (my $line2 = <FILE>); next if not $line1 =~ /red line/; print($line1, $line2); }
Re: Extracting Data from a second line
by GrandFather (Saint) on Feb 17, 2006 at 04:28 UTC

    There is more than one way to determine what constitutes a line:

    use strict; use warnings; local $/ = "A red line is found\n"; while (<DATA>) { print "Red line $1" if /(at location[^\n]*\n)/; } __DATA__ A red line is found at location 2.5 4.5 A Blue line is found at location 2.6 4.5 A red line is found at location 2.67 4.56 The red arc is found at location 2.5 4.5

    Prints:

    Red line at location 2.5 4.5 Red line at location 2.67 4.56

    DWIM is Perl's answer to Gödel
Re: Extracting Data from a second line
by BrowserUk (Patriarch) on Feb 17, 2006 at 05:40 UTC

    Read two lines at a time and concatenate them. Use /s on the regex to allow '.' to match the newline.

    #! perl -slw use strict; m[red line.*location (\S+) (\S+)\n]s and print "($1, $2)" while $_ = <DATA> . <DATA>; __DATA__ A red line is found at location 2.5 4.5 A Blue line is found at location 2.6 4.5 A red line is found at location 2.67 4.56 The red arc is found at location 2.5 4.5

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks to ALL of those that replied, these insights were exactly what I needed to get the information I wanted. RCP