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

Hi, I have to parse some text files, there's a keyword I'm looking for on a line, all lines thereafter I need returned until the lines are composed solely of spaces (non-char/numbers) again. I tried something like:
print line until (!($line =~ /\s+/)) Filecontents e.g. ----------------- [spaces] Keyword relevant line relevant line relevant line [spaces] ----------

Replies are listed 'Best First'.
Re: Until there's nothing but spaces?
by CubicSpline (Friar) on Sep 30, 2001 at 22:28 UTC
    assuming that you're reading from the file into the variable $line, you may want to change that line to
    print $line until(!($line =~ /\s+/))
    . However this doesn't look like this is quite what you want. That regex will match every line in the text (\s matches newlines). I'd switch your regex to be looking for word characters, so that once the line doesn't have any word characters, you exit your loop. I would do something like this:

    use strict; use warnings; my $line; open IN,"lines.txt"; while($line = <IN>) { print $line unless(!($line =~ /\w+/)); }
Re: Until there's nothing but spaces?
by lestrrat (Deacon) on Sep 30, 2001 at 22:32 UTC

    not exactly sure what your

    print line until ( !($line =~ /\s+/ ) )

    means, but here's a pseudocode that I _think_ is close to what you want:

    while( my $ln = <$filehandle> ) { next if $ln =~ /^\s*$/; if( $ln .... [ your conditions ] ) { while( $ln = <$filehandle> ) { last if $line =~ /\s*$/; print $line; # or whatever } } }
Re: Until there's nothing but spaces?
by tachyon (Chancellor) on Sep 30, 2001 at 23:03 UTC
    open FH, $some_file or die "Can't open $some_file, Perl says $!\n"; LOOP: while (<FH>) { next until /$some_cond/; while (<FH>) { last LOOP if /^\s$/; print; } }

    Edit $some_file and $some_cond to suit. We use the default aliasing to $_ in our while loops, regex match and print.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Until there's nothing but spaces?
by Anonymous Monk on Sep 30, 2001 at 23:16 UTC
    O.K. this is how I solved it, it seems to work pretty well. Tnx to all for their help!
    opendir (ID, "$dir"); @dirlist = readdir(ID); closedir(ID); foreach $inode (@dirlist) { $i++; print "Files processed: $i\n"; next if $inode =~ /^\./; my $sfile = $dir . $inode; open (IF, "<$sfile"); @fcont = (<IF>); close (IF); open (OF, ">$sfile"); foreach $line (@fcont) { if ($line =~ /themark/) { print "starter string found\n"; $flag = 1; next; } if ($flag == 1) { if (!($line =~ /\w+/)) { $flag = 0; next; } else { print OF $line; } } } close (OF); }
      next if $inode =~ /^\./;
      ...looks like it will match .bashrc .login .hidden_data and skip them.

      If you only want to skip '..' and '.' something you may want something (untested) like this:

      m/^\.{1,2}$/


      --mandog

        Good thing you pointed out that this code is untested, because it is wrong! Someone posted this very same snippet a couple of weeks ago and merlyn pointed out a subtle way in which it can fail.

        But rather than elaborating a more and more complex regexp for such a simple operation, I like to spell things out more simply, but using something like:

          next if $inode eq '.' or $inode eq '..';

        This avoids pulling in the regexp machinery, and is much easier for the next maintainer (who may not be as good a rexexp wizard as yourself) to figure out what is going on.

        --
        g r i n d e r
Re: Until there's nothing but spaces?
by gbarr (Monk) on Oct 01, 2001 at 17:35 UTC
    Wow there have been several different responses to this question, but not one has mentioned the operator that is designed to do just what you ask, that is the .. operator.

    print if (/^Keyword$/../^\s*$/)||0 > 1 and /\S/;

    OK, so what does this do. Well the .. operator will return false until the LHS is true. It then returns a true value, this value will initially be 1 but will increment each time, until the RHS becomes true. But it will return true on the line where the RHS is true, so we add the /\S/ check to prevent the output of the last line.

    The || 0 is there as for false .. returns "", which -w will complain about.

Re: Until there's nothing but spaces?
by ariels (Curate) on Oct 01, 2001 at 10:58 UTC
    Note that $line =~ /\s+/ (or $line =~ /\s/) matches every line containing whitespace. Including something like "white space". Negating, you're looping until the first line with no whitespace at all. If you're chomping your lines (not clear from your code), that's a line consisting of a single word, not a blank one! If you're not, every line will match (the \n at the end is whitespace).

    The correct thing to match is $line !~ /^\s*$/. But there's no need to negate a regexp here; instead, try looking for a line containing a non-whitespace char: $line =~ /\S/ is the idiomatic Perl for this.