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

I inherited a program that I'm converting from Tk to CGI (orders is orders). The original author has no clue what he did, as it was 4+ years ago and he's managed several projects since then. (And, no, there's no commenting or documentation.) Basically, it takes a set of datafiles, munges them, then displays them in some fashion.

During the data-munging part, I found the following line of code:

next LINE while (($line =~ /abcd/o) .. ($line =~ /def/0)); I'm a little confused as to what it does. As far as I know, those conditions never arise, as they're checked for above. But, what would this do?? (And, yes, it compiles and runs just fine.)

Replies are listed 'Best First'.
Re: This code is just freaky...
by arturo (Vicar) on Jul 27, 2001 at 21:47 UTC

    It's a funky snippet that processes a certain block of lines in the file. Specifically, this code ignores lines between ones that contain "abcd" and ones that contain "def".

    The next tells you the code goes back to the block with the label LINE (so nothing in the loop below this line gets executed), and it does so while the following condition is true :

    from the point that $line matches "abcd" to the point where it matches "def"

    The range operator .. is the key here; notice that it occurs in scalar context, not list context. It's false until the regex on the left matches, where it flips to true, and remains true until the regex on the right matches.

    Read it as "everything in between" and you'll have a good idea of what's going on here (that works for how it operates in list context, too)

    This behavior is documented in perlop, under the heading "Range operators".

    HTH!

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
      I figured it out! The range operator stuff freaked me out a little, but the big trick is that

      foreach my $a (1 .. 5) { next while ($a != 2); }
      won't go to the while it's next to, but the outer foreach loop. Thus, you don't enter an infinite loop.

      A curious thing was that I wrote the quick program:

      my @strings = ('a', 'b', 'c', 'd', 'e', 'f'); while (my $s = shift @strings) { print "Looking at $s\n"; next while ($s =~ /a/ .. $s =~ /c/); print "$s is OK!\n"; }
      How does the range-op-boolean know that $s was a in a previous check. It seems to be maintaining state between invocations.

      Update:

      my @strings = ('a', 'b', 'c', 'd', 'e', 'f'); while (my $s = shift @strings) { print "Looking at $s\n"; my $value = $s =~ /a/ .. $s =~ /c/; print "The value is $value\n"; next if $value; print "$s is OK!\n"; }
      This gives a very interesting output.

      Looking at a The value is 1 Looking at b The value is 2 Looking at c The value is 3E0 Looking at d The value is d is OK! Looking at e The value is e is OK! Looking at f The value is f is OK!
      I just find that '3E0' thing really odd...
        I love the flip-flop operator. The description in older Camel books is classic. Its befuddling until you get through the whole thing, and great to impress other (non-Perl) programmers with.

        The E0 suffix thing is a bit clunky. Perl 6 should do that better, using properties.

        —John

        '3E0' is a variation on "0 but true". You can discover that it's the last line by matching /E0$/
        (efficiency:  index $value,'E0' >= 0), or treat it as a number, which yields 3.

          p

Re: This code is just freaky...
by snafu (Chaplain) on Jul 27, 2001 at 22:20 UTC
    I am still very new to the world of Perl. I would like to take a stab at this. I do believe that this might be the use of the operator called the flip-flop operator that deals with eof's but it seems kind of tweaked. According to Programming Perl 2nd Edition on page 160 there is a block of code that looks *kind* of similar to what you are showing:

    while (<>) { print if /pattern/ .. eof; }
    Of course the biggest difference being the use of the actual eof() function.

    The only other thing I can see here is the possiblity of looking for a range of patterns using the .. operator which in all honesty seems more likely than my above perception.

    I'd actually like to use the flip-flop operator sometime. Anyone have any experience with it?

    ----------
    - Jim

Re: This code is just freaky...
by Zaxo (Archbishop) on Jul 27, 2001 at 22:01 UTC

    LINE appears to refer to a label, so you could look for a labeled bareblock, 'LINE: {...}' enclosing this line of code.

    The effect of while (($line =~ /abcd/o) .. ($line =~ /def/0)) is to skip back to the label (presumably to read another $line) when $line has matched 'abcd' but not yet matched 'def'. I have no idea what the '0' does, but it might be a typo for 'o'.

    This construction will fail if abcd-def pairs can nest.

    After Compline,
    Zaxo

      I think you are right, the '0' is a typo for 'o', which tells the regex compiler to only compile each regex once for the entire program, not once for every loop iteration.
      You might not see an explicit block with the label LINE:, as that is the label given to the implicit loop when perl is called with the -n or -p command line switch. -C.
Re: This code is just freaky...
by mattr (Curate) on Jul 30, 2001 at 12:51 UTC
    Looks like that 0 is a typo.
    Suppose precedence makes parens unneccesary too but hooray for parens!
    perl -MO=Deparse -e 'next LINE while (($line =~ /abcd/o) .. ($line =~ /def/0));' Number found where operator expected at -e line 1, near "/def/0" (Missing operator before 0?) syntax error at -e line 1, near "/def/0" -e had compilation errors. ; perl -MO=Deparse -e 'next LINE while (($line =~ /abcd/o) .. ($line =~ /def/o));' -e syntax OK next LINE while $line =~ /abcd/o .. $line =~ /def/o;