FAQ
# Print lines (or not) until a blank line is found (or not)

# This function works fine. But in the spirit of learning...read on.

sub print_lines_ok {

my ($output, $blank_lines) = @_;

if ($blank_lines) {
do {
print if $output;

$_ = <>;

} while (/^\s*$/ and not eof);
} else {
do {
print if $output;

$_ = <>;

} while (not /^\s*$/ and not eof);
}
}


# This function is the same thing; just more 'elegant' IMHO. :-)
# But it has its problems. I can eval it in the while loop and it
# works as it is below, but it's painfully slow. I *know* there's no
# need for the eval call every iteration but so far haven't figured
# out how to use eval outside the while AND have it work. It
# appears $expr is always true unless the eval is done in the while loop.
# In summary, how can I build a dynamic regexp that I can eval once
# and then use?


sub print_lines_ideal {

my ($output, $blank_lines) = @_;
my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';

# eval $expr # I want to eval this ONCE and then use it. Help?


do {
print if $output;

$_ = <>;

} while (eval $expr and not eof); # works, but not fast.
# Can I move eval out of loop?
}


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free web site building tool. Try it!
http://webhosting.yahoo.com/ps/sb/

Search Discussions

  • Rob Dixon at Jan 28, 2004 at 5:24 am

    Sam wrote:
    # Print lines (or not) until a blank line is found (or not)

    # This function works fine. But in the spirit of learning...read on.

    sub print_lines_ok {

    my ($output, $blank_lines) = @_;

    if ($blank_lines) {
    do {
    print if $output;

    $_ = <>;

    } while (/^\s*$/ and not eof);
    } else {
    do {
    print if $output;

    $_ = <>;

    } while (not /^\s*$/ and not eof);
    }
    }


    # This function is the same thing; just more 'elegant' IMHO. :-)
    # But it has its problems. I can eval it in the while loop and it
    # works as it is below, but it's painfully slow. I *know* there's no
    # need for the eval call every iteration but so far haven't figured
    # out how to use eval outside the while AND have it work. It
    # appears $expr is always true unless the eval is done in the while loop.
    # In summary, how can I build a dynamic regexp that I can eval once
    # and then use?


    sub print_lines_ideal {

    my ($output, $blank_lines) = @_;
    my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';

    # eval $expr # I want to eval this ONCE and then use it. Help?


    do {
    print if $output;

    $_ = <>;

    } while (eval $expr and not eof); # works, but not fast.
    # Can I move eval out of loop?
    }
    I don't think you want what you've written, as the first call to 'print'
    is before anything has been read from the file. This should come close:

    sub print_lines {

    my ($output, $blank_lines) = @_;

    while (<>) {
    last if $blank_lines xor /\S/;
    print if $output;
    }
    }


    Rob
  • Jeff 'japhy' Pinyan at Jan 28, 2004 at 8:29 am
    On Jan 27, Rob Dixon said:
    Sam wrote:
    sub print_lines_ok {
    my ($output, $blank_lines) = @_;
    if ($blank_lines) {
    do {
    print if $output;
    $_ = <>;
    } while (/^\s*$/ and not eof);
    } else {
    do {
    print if $output;
    $_ = <>;
    } while (not /^\s*$/ and not eof);
    }
    }


    sub print_lines_ideal {
    my ($output, $blank_lines) = @_;
    my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';

    do {
    print if $output;
    $_ = <>;
    } while (eval $expr and not eof); # works, but not fast.
    # Can I move eval out of loop?
    }
    You could just say

    do ... while (($blank ? /^\s*$/ : not /^\s*$/) and not eof);

    which could be written with 'xor' as Rob shows below:

    do ... while ($blank xor not /^\s*$/) and not eof;

    and 'not /^\s*$/' can be written as /\S/, which results in Rob's code.
    I don't think you want what you've written, as the first call to 'print'
    is before anything has been read from the file. This should come close:

    sub print_lines {
    my ($output, $blank_lines) = @_;
    while (<>) {
    last if $blank_lines xor /\S/;
    print if $output;
    }
    }
    That might work in this specific case, but if you want to be able to
    change the course of events like that without constant re-evaluation, I'd
    suggest using code references:

    my $code = \&first;

    sub first {
    # code for the first case
    if (some condition) { $code = \&second }
    }

    sub second {
    # code for the second case
    }

    $code->();

    --
    Jeff "japhy" Pinyan japhy@pobox.com http://www.pobox.com/~japhy/
    RPI Acacia brother #734 http://www.perlmonks.org/ http://www.cpan.org/
    <stu> what does y/// stand for? <tenderpuss> why, yansliterate of course.
    [ I'm looking for programming work. If you like my work, let me know. ]
  • Sam at Jan 28, 2004 at 5:26 pm
    Thanks for all your responses; I learned a bit.

    1. I wasn't clear on $_ in my email; that's being read elsewhere in program so
    it's already set by the time print_lines is called.

    2. Will you bet your life on this equivalence: "not /^\s*$/ == /\S/"? I
    believe it's safer to negate an EXPR than to find some other EXPR2 that is
    equivalent to 'not EXPR'.

    3. Hadn't thought about xor; good to know.

    4. As for the generalized case, I learned about using refs. Anonymous subs
    also work.

    my $re = sub { return /^\s*$/; };
    my $nre = sub { return not &$re; };
    my $expr = $blank ? $re : $nre;
    do ... while (&$expr and not eof);

    But I'm not sure which is faster though.

    Thanks for all your help.

    --- Jeff 'japhy' Pinyan wrote:
    On Jan 27, Rob Dixon said:
    Sam wrote:
    sub print_lines_ok {
    my ($output, $blank_lines) = @_;
    if ($blank_lines) {
    do {
    print if $output;
    $_ = <>;
    } while (/^\s*$/ and not eof);
    } else {
    do {
    print if $output;
    $_ = <>;
    } while (not /^\s*$/ and not eof);
    }
    }


    sub print_lines_ideal {
    my ($output, $blank_lines) = @_;
    my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';

    do {
    print if $output;
    $_ = <>;
    } while (eval $expr and not eof); # works, but not fast.
    # Can I move eval out of loop?
    }
    You could just say

    do ... while (($blank ? /^\s*$/ : not /^\s*$/) and not eof);

    which could be written with 'xor' as Rob shows below:

    do ... while ($blank xor not /^\s*$/) and not eof;

    and 'not /^\s*$/' can be written as /\S/, which results in Rob's code.
    I don't think you want what you've written, as the first call to 'print'
    is before anything has been read from the file. This should come close:

    sub print_lines {
    my ($output, $blank_lines) = @_;
    while (<>) {
    last if $blank_lines xor /\S/;
    print if $output;
    }
    }
    That might work in this specific case, but if you want to be able to
    change the course of events like that without constant re-evaluation, I'd
    suggest using code references:

    my $code = \&first;

    sub first {
    # code for the first case
    if (some condition) { $code = \&second }
    }

    sub second {
    # code for the second case
    }

    $code->();

    --
    Jeff "japhy" Pinyan japhy@pobox.com http://www.pobox.com/~japhy/
    RPI Acacia brother #734 http://www.perlmonks.org/ http://www.cpan.org/
    <stu> what does y/// stand for? <tenderpuss> why, yansliterate of course.
    [ I'm looking for programming work. If you like my work, let me know. ]


    --
    To unsubscribe, e-mail: beginners-unsubscribe@perl.org
    For additional commands, e-mail: beginners-help@perl.org
    <http://learn.perl.org/> <http://learn.perl.org/first-response>

    __________________________________
    Do you Yahoo!?
    Yahoo! SiteBuilder - Free web site building tool. Try it!
    http://webhosting.yahoo.com/ps/sb/
  • Rob Dixon at Jan 28, 2004 at 6:12 pm

    Sam wrote:
    Thanks for all your responses; I learned a bit.
    Good: well done.
    1. I wasn't clear on $_ in my email; that's being read elsewhere in program so
    it's already set by the time print_lines is called.
    You /mustn't/ use $_ like that. It's meant to be an 'it' in places like

    For each banana, look at it, smell it, and eat it.

    NOT

    When I say 'it', it means 'banana 3 from crate 5'.
    For each apple, look at it, smell it, and eat it.
    Do it to it.
    2. Will you bet your life on this equivalence: "not /^\s*$/ == /\S/"? I
    believe it's safer to negate an EXPR than to find some other EXPR2 that is
    equivalent to 'not EXPR'.
    Yes. (But I can think of more valuable things to bet on.)

    The first says,

    Does the entire string, from start to end, consist of zero or more 'space' characters?

    The second says,

    Does the string contain a non-'space' character anywhere?

    The only difficulty could be with a zero-length string, which is still fine, if
    you think about it.
    3. Hadn't thought about xor; good to know.
    Be careful though. 'xor' goes with the other low-precedence operators 'and'
    and 'or', which have the high-precedence equivalents && and ||. 'xor' has
    no equivalent. (The caret, ^, is a bitwise operator, which is completely
    different.)
    4. As for the generalized case, I learned about using refs. Anonymous subs
    also work.

    my $re = sub { return /^\s*$/; };
    my $nre = sub { return not &$re; };
    Eek. Don't do that. It may work, but it's not at all obvious what $_ is in the
    context of a subroutine call. Having $nre dereference $re at each call isn't
    your best bet either.
    my $expr = $blank ? $re : $nre;
    do ... while (&$expr and not eof);
    The better syntax for a call to a subroutine reference is

    $expr->()

    which doesn't assume all sorts of things that could keep you awake at night if
    you knew.
    But I'm not sure which is faster though.
    If you don't know, it doesn't matter.

    If your software is /too/ slow and you would die for a 10% speed increase then
    check out

    use Benchmark;

    If not, don't bother.

    HTH,

    Rob
  • Sam at Jan 28, 2004 at 9:19 pm

    --- Rob Dixon wrote:
    Sam wrote:
    Thanks for all your responses; I learned a bit.
    Good: well done.
    1. I wasn't clear on $_ in my email; that's being read elsewhere in
    program so
    it's already set by the time print_lines is called.
    You /mustn't/ use $_ like that. It's meant to be an 'it' in places like
    What? You want me to pass the line around in a variable! :-)
    For each banana, look at it, smell it, and eat it.

    NOT

    When I say 'it', it means 'banana 3 from crate 5'.
    For each apple, look at it, smell it, and eat it.
    Do it to it.
    2. Will you bet your life on this equivalence: "not /^\s*$/ == /\S/"? I
    believe it's safer to negate an EXPR than to find some other EXPR2 that is
    equivalent to 'not EXPR'.
    Yes. (But I can think of more valuable things to bet on.)

    The first says,

    Does the entire string, from start to end, consist of zero or more 'space'
    characters?

    The second says,

    Does the string contain a non-'space' character anywhere?

    The only difficulty could be with a zero-length string, which is still fine,
    if
    you think about it.
    I hear 'ya, but I like to avoid possible boundary conditions that make me think
    'what if.' Just using 'not' avoids that mess. In this case the re was simple
    enough, but w/more complex ones...
    3. Hadn't thought about xor; good to know.
    Be careful though. 'xor' goes with the other low-precedence operators 'and'
    and 'or', which have the high-precedence equivalents && and ||. 'xor' has
    no equivalent. (The caret, ^, is a bitwise operator, which is completely
    different.)
    4. As for the generalized case, I learned about using refs. Anonymous subs
    also work.

    my $re = sub { return /^\s*$/; };
    my $nre = sub { return not &$re; };
    Eek. Don't do that. It may work, but it's not at all obvious what $_ is in
    the
    context of a subroutine call. Having $nre dereference $re at each call isn't
    your best bet either.
    my $expr = $blank ? $re : $nre;
    do ... while (&$expr and not eof);
    The better syntax for a call to a subroutine reference is

    $expr->()

    which doesn't assume all sorts of things that could keep you awake at night
    if
    you knew.
    Ok, that's good to know.
    But I'm not sure which is faster though.
    If you don't know, it doesn't matter.

    If your software is /too/ slow and you would die for a 10% speed increase
    then
    check out

    use Benchmark;

    If not, don't bother.
    No it hums along fine. But using eval was *really* slow and clearly I was on
    the wrong track using it.

    Thanks.
    HTH,

    Rob



    --
    To unsubscribe, e-mail: beginners-unsubscribe@perl.org
    For additional commands, e-mail: beginners-help@perl.org
    <http://learn.perl.org/> <http://learn.perl.org/first-response>

    __________________________________
    Do you Yahoo!?
    Yahoo! SiteBuilder - Free web site building tool. Try it!
    http://webhosting.yahoo.com/ps/sb/
  • John W. Krahn at Jan 29, 2004 at 1:49 am

    Sam wrote:

    --- Rob Dixon wrote:
    Sam wrote:
    But I'm not sure which is faster though.
    If you don't know, it doesn't matter.

    If your software is /too/ slow and you would die for a 10% speed increase
    then
    check out

    use Benchmark;

    If not, don't bother.
    No it hums along fine. But using eval was *really* slow and clearly I was on
    the wrong track using it.
    It depends on how you use eval. :-) Instead of using eval inside of a
    loop it is a lot faster if you eval the whole loop.

    # slow
    my $expr = '/$regex/';
    while ( <FILE> ) {
    if ( eval $expr ) {
    do { something() };
    }
    }

    # a lot faster
    my $loop = <<'LOOP';
    while ( <FILE> ) {
    if ( /$regex/ ) {
    do { something() };
    }
    }
    LOOP
    eval $loop;




    John
    --
    use Perl;
    program
    fulfillment
  • Rob Dixon at Jan 29, 2004 at 3:31 pm

    John W. Krahn wrote:
    Instead of using eval inside of a loop it is a
    lot faster if you eval the whole loop.

    # slow
    my $expr = '/$regex/';
    while ( <FILE> ) {
    if ( eval $expr ) {
    do { something() };
    }
    }

    # a lot faster
    my $loop = <<'LOOP';
    while ( <FILE> ) {
    if ( /$regex/ ) {
    do { something() };
    }
    }
    LOOP
    eval $loop;
    Nice one John. Thanks.

    Rob
  • Rob Dixon at Jan 29, 2004 at 1:26 pm

    Sam wrote:
    Rob wrote:
    Sam wrote:
    1. I wasn't clear on $_ in my email; that's being read elsewhere in
    program so it's already set by the time print_lines is called.
    You /mustn't/ use $_ like that. It's meant to be an 'it' in places like
    What? You want me to pass the line around in a variable! :-)
    Yes. $_ is magical, and there's no excuse that I can think of for
    assigning to it directly. If you have a tiny block that needs to use
    the same value several times then use the idiom

    for ($thisvalue) {
    :
    }

    Rob
  • Tassilo von Parseval at Jan 28, 2004 at 10:29 pm

    On Wed, Jan 28, 2004 at 09:11:51AM -0800 Sam wrote:

    4. As for the generalized case, I learned about using refs. Anonymous subs
    also work.

    my $re = sub { return /^\s*$/; };
    my $nre = sub { return not &$re; };
    my $expr = $blank ? $re : $nre;
    do ... while (&$expr and not eof);

    But I'm not sure which is faster though.
    These function-refs look fishy. All they do is carrying out a pattern
    match. By using '&$expr' you'll also have perl pass on the current
    content of @_ to the function which is wasteful since you are not
    interested in the arguments.

    In this case you better just use pre-compiled regexes:

    my $re = qr/^\s*$/;
    my $nre = qr/\S/; # !qr/^\s*$/ wont work unfortunately
    my $pat = $blank ? $re : $nre;
    do ... while /$pat/o and not eof;

    This has the disadvantage that there is no generalized way of negating a
    pattern. You have to do that manually. Or you create a slightly more
    complicated condition:

    do ... while ($blank && /$re/) || !/$re/ and not eof;

    Tassilo
    --
    $_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
    pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
    $_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval
  • John W. Krahn at Jan 28, 2004 at 10:33 pm

    Sam wrote:

    Thanks for all your responses; I learned a bit.

    1. I wasn't clear on $_ in my email; that's being read elsewhere in program so
    it's already set by the time print_lines is called.

    2. Will you bet your life on this equivalence: "not /^\s*$/ == /\S/"?
    Yes I will. :-)


    Another point that I just noticed is that you are using eof with the <>
    special readline operator. You DO realize that eof (without
    parenthesis) behaves differently than eof() or eof(ARGV) when using <>?



    John
    --
    use Perl;
    program
    fulfillment
  • John W. Krahn at Jan 28, 2004 at 2:02 pm

    Sam wrote:

    # Print lines (or not) until a blank line is found (or not)
    # This function works fine. But in the spirit of learning...read on.

    sub print_lines_ok {
    my ($output, $blank_lines) = @_;
    if ($blank_lines) {
    do {
    print if $output;
    You are printing the contents of $_ but you don't have anything in $_
    until the next line.

    $_ = <>;
    } while (/^\s*$/ and not eof);
    } else {
    do {
    print if $output;
    $_ = <>;
    } while (not /^\s*$/ and not eof);
    }
    }

    # This function is the same thing; just more 'elegant' IMHO. :-)
    # But it has its problems. I can eval it in the while loop and it
    # works as it is below, but it's painfully slow. I *know* there's no
    # need for the eval call every iteration but so far haven't figured
    # out how to use eval outside the while AND have it work. It
    # appears $expr is always true unless the eval is done in the while loop.
    # In summary, how can I build a dynamic regexp that I can eval once
    # and then use?

    sub print_lines_ideal {
    my ($output, $blank_lines) = @_;
    my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';
    # eval $expr # I want to eval this ONCE and then use it. Help?
    do {
    print if $output;
    $_ = <>;
    } while (eval $expr and not eof); # works, but not fast.
    # Can I move eval out of loop?
    }
    Perhaps this is what you want:

    sub print_lines_ideal {
    my ( $output, $blank_lines ) = @_;
    my $expr = $blank_lines ? qr/^\s*$/ : qr/\S/;
    while ( <> ) {
    print if $output and /$expr/;
    }
    }



    John
    --
    use Perl;
    program
    fulfillment
  • Rob Dixon at Jan 28, 2004 at 5:19 pm

    John W. Krahn wrote:
    Sam wrote:
    # Print lines (or not) until a blank line is found (or not)
    # This function works fine. But in the spirit of learning...read on.

    sub print_lines_ok {
    my ($output, $blank_lines) = @_;
    if ($blank_lines) {
    do {
    print if $output;
    You are printing the contents of $_ but you don't have anything in $_
    until the next line.

    $_ = <>;
    } while (/^\s*$/ and not eof);
    } else {
    do {
    print if $output;
    $_ = <>;
    } while (not /^\s*$/ and not eof);
    }
    }

    # This function is the same thing; just more 'elegant' IMHO. :-)
    # But it has its problems. I can eval it in the while loop and it
    # works as it is below, but it's painfully slow. I *know* there's no
    # need for the eval call every iteration but so far haven't figured
    # out how to use eval outside the while AND have it work. It
    # appears $expr is always true unless the eval is done in the while loop.
    # In summary, how can I build a dynamic regexp that I can eval once
    # and then use?

    sub print_lines_ideal {
    my ($output, $blank_lines) = @_;
    my $expr = $blank_lines ? '/^\s*$/' : 'not /^\s*$/';
    # eval $expr # I want to eval this ONCE and then use it. Help?
    do {
    print if $output;
    $_ = <>;
    } while (eval $expr and not eof); # works, but not fast.
    # Can I move eval out of loop?
    }
    Perhaps this is what you want:

    sub print_lines_ideal {
    my ( $output, $blank_lines ) = @_;
    my $expr = $blank_lines ? qr/^\s*$/ : qr/\S/;
    while ( <> ) {
    print if $output and /$expr/;
    }
    }
    Hi John.

    It's hard to be sure, as we're guessing what the required algorithm is; but
    the original code dropped out at the /first/ line that failed the blank or
    non-blank test. Your solution may need to be:

    while ( <> ) {
    last unless /$expr/;
    print if $output;
    }

    which I must say looks rather neat :)

    Rob

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupbeginners @
categoriesperl
postedJan 27, '04 at 5:43p
activeJan 29, '04 at 3:31p
posts13
users5
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase