Some time ago I was preparing some presentation about Perl and while reading about flip-flop I was wondering how to easily explain how it works. I couldn't. It works in such intuitive way one can tell "get me everything between /start/ and /stop/". But to explain how it does it, you need two pages of paper :) Ok, I exaggerate a little. Anyway, I discovered another useful construction with the same properties: it can be easily described as "take everything between /start/ and (/end/ which is not inside other /start/ .. /end/ block)". Or shorter: "take /start/ .. /end/ block which can include other /start/ .. /end/ blocks", but kids don't try to analyze it at home :) It can be easily extended to two or more levels of nesting. Pity, I didn't discover it before 'beautiful Perl YAPC'... :)
#!perl while(<DATA>) { if(/start/ .. (!(/start/../end/) && /end/)) { print } } __DATA__ a a a start b start c d e end f start g h i end j end k k l

Replies are listed 'Best First'.
Re: Beautiful .. operator
by ikegami (Patriarch) on Oct 28, 2008 at 21:15 UTC

    take everything between /start/ and /end/ which is not inside other /start/ .. /end/ block

    That would be
    start b f j end
    but I get
    start b start c d e end start g h i end
      Sorry, my mistake. Original if(/start/ .. (/end/ && !(/start/../end/))) replaced with if(/start/ .. (!(/start/../end/) && /end/)) And description changed to: take everything between /start/ and (/end/ which is not inside other /start/ .. /end/ block)

        take everything between /start/ and (/end/ which is not inside other /start/ .. /end/ block)

        That would be

        start b f j end

        but I get

        start b start c d e end f start g h i end j end

        from /start/ .. (!(/start/../end/) && /end/)

Re: Beautiful .. operator
by Sandy (Curate) on Oct 28, 2008 at 22:34 UTC
    No, it still doesn't do what you advertise:

    #!/usr/bin/perl use strict; use warnings; our $data; print "\n\n original\n"; foreach (split("\n",$data)) { if(/start/ .. (!(/start/../end/) && /end/)) { print "$_\n"} } print "\n\n analysis:\n"; print " - note that range operator is set to true when \$flag1 is t +rue\n"; print " becomes false only after \$flag3 has been set to tru +e\n"; print "\n"; foreach (split("\n",$data)) { my $flag1=0;my $flag2 = 0;my $flag3=0; $flag1 = 1 if (/start/); $flag2 = 1 if (/start/../end/); $flag3 = 1 if (!$flag2 && /end/); print "$flag1, $flag2, $flag3, $_",' 'x(15-length($_)); if(/start/ .. (!(/start/../end/) && /end/)) { print "success\n"} else {print "\n";} } BEGIN { our $data = << 'TEST'; a a a start b start c d e end f start g h i end j end k k l TEST }

    result

    original start b start c d e end f start g h i end j end analysis: - note that range operator is set to true when $flag1 is true becomes false only after $flag3 has been set to true 0, 0, 0, a 0, 0, 0, a 0, 0, 0, a 1, 1, 0, start success 0, 1, 0, b success 1, 1, 0, start success 0, 1, 0, c success 0, 1, 0, d success 0, 1, 0, e success 0, 1, 0, end success 0, 0, 0, f success 1, 1, 0, start success 0, 1, 0, g success 0, 1, 0, h success 0, 1, 0, i success 0, 1, 0, end success 0, 0, 0, j success 0, 0, 1, end success 0, 0, 0, k 0, 0, 0, k 0, 0, 0, l