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

hi i have a quick program here to output some data to the screen.
#!usr/local/bin/perl my $path='CustData.txt'; open(DATA, "<$path") || die "Couldn't open $path for reading: $!\n"; while (<DATA>) { chomp; my ($id, $title, $surname, $forename, $sex, $dob, $vision) = split +(/,/); $HoH{$id} = {'title' => $title, 'surname' => $surname, 'forename' +=> $forename, 'sex' => $sex, 'dob' => $dob, 'vision' => $vision,}; } close(DATA); $range1=1; $range2=10; $range3=1; $range4=10; $person_count=0; print("Range\t10-20\t20-30\t30-40\t41-50\t51-60\t61-70\t71-80\t81-90\t +91-99\n"); print("Count"); for ($counter=0;$counter<9;$counter++) { $range3=$range3+10; $range4=$range4+10; print("\t ".personCount($range3,$range4)); } print("\n"); print("Percent\t"); for ($counter=0;$counter<9;$counter++) { $range1=$range1+10; $range2=$range2+10; printf(" %.0f\t",(percent($range1,$range2))); } print("\n"); sub personCount { ($x,$y) = @_; my ($vision_total,$person_count)=0; foreach my $id (sort keys %HoH) { if( ($HoH{$id}->{'vision'}>=$x) & ($HoH{$id}->{'vision'}<=$y) +) { ++$person_count; $vision_total=$vision_total+$HoH{$id}->{'vision'}; } } return int($person_count); } sub percent { ($x,$y) = @_; $percent = 0; my ($total_person_count,$vision_total,$person_count)=0; foreach my $id (sort keys %HoH) { ++$total_person_count; } foreach my $id (sort keys %HoH) { if( ($HoH{$id}->{'vision'}>=$x) & ($HoH{$id}->{'vision'}<=$y) +) { ++$person_count; $vision_total=$vision_total+$HoH{$id}->{'vision'}; } } return $percent = ($person_count/$total_person_count)*100; }
i want to be able to choose wHether to output this to the screen or to a file. at the moment i can only work out how to output it to the screen. how can i change my code so that instead of printing to the screen it returns a value. ie the section of the code here:
$range1=1; $range2=10; $range3=1; $range4=10; $person_count=0; print("Range\t10-20\t20-30\t30-40\t41-50\t51-60\t61-70\t71-80\t81-90\t +91-99\n"); print("Count"); for ($counter=0;$counter<9;$counter++) { $range3=$range3+10; $range4=$range4+10; print("\t ".personCount($range3,$range4)); } print("\n"); print("Percent\t"); for ($counter=0;$counter<9;$counter++) { $range1=$range1+10; $range2=$range2+10; printf(" %.0f\t",(percent($range1,$range2))); } print("\n");
instead of using print and printf, how do i make it so that that little bit to be printed is stored for later so that when the user chooses to output you can choose to print or save to a file. basically my question is can you have a print statement made into a variable to be used for later? or is this the wrong way of going about this???

Replies are listed 'Best First'.
Re: print to data
by Hue-Bond (Priest) on Sep 06, 2006 at 11:39 UTC

    Besides the push solution, you can also print to a filehandle that has been opened to an in-memory variable:

    my $output; open my $fd, '>', \$output or die "open: $!"; ## print to the $output scalar print $fd "hello\n"; print $fd "world\n"; close $fd; ## use results print $output; __END__ hello world

    --
    David Serrano

      Opening scalar refs is one of my favorite newish features of perl. Keep in mind that this works for perl 5.8 and above. For earlier versions you would have to use IO::Scalar or IO::String.
      Hue-Bond: thanks, that was a fantastic idea. it worked perfectly! cheers!
Re: print to data
by GrandFather (Saint) on Sep 06, 2006 at 11:29 UTC

    use sprintf instead of printf and push the resulting strings to an array for later use:

    my @fragments; push @lines, sprintf "Percent\t"; for (...) { ... push @fragments, sprintf ...; } push @lines, join '', @fragments;

    DWIM is Perl's answer to Gödel
Re: print to data
by shmem (Chancellor) on Sep 06, 2006 at 12:00 UTC
    Besides them two, you could define your custom print routine, e.g. cprint for conditional print.
    # set up an array at the top of your program my @output; # set up a flag my $capture = 0; sub cprint { $capture ? (print @_) : push(@output,@_); }
    and change all your print statements to cprint. Setting $capture to 1 results in filling the array @output.

    Another hint: Don't use - even for quick hacks - the DATA filehandle for regular files, the DATA filehandle is special. See e.g. perldata.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      i dont quite understand the custom print routine you just described above. can you explain in a little bit more detail please. thanks.
        sub cprint { $capture ? (print @_) : push(@output,@_); }

        is short for

        sub cprint { if($capture) { # if $capture is != 0, '' or undef print @_; # print what's passed in } else { # otherwise push(@output,@_); # stuff goes into @output } }

        See the section Conditional Operator in perlop for $foo ? $bar : $quux.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}