Re: returning to a loop later on
by ikegami (Patriarch) on Sep 07, 2006 at 01:45 UTC
|
- You didn't turn on warnings. (You'd get a lot of them if they were on.)
- You didn't turn on strict, or your declared your variables too far from where they should be declared.
- You are printing "Invalid input" whether the input is good or bad.
- Using {1} in regexps is useless.
- You shouldn't be using regexps for constant strings.
- Why use the 2-arg open when you can use the 3-arg one? At least your file name has been validated (although possibly too strictly).
- Your file handle isn't localized. It would be even better if it was a lexical variable.
- You say an extention will be added, but you it isn't.
- You're printing too many newlines.
- You accept more file names than the error message indicates. This is not necessarily wrong.
Fix:
#!/usr/bin/perl
use strict;
use warnings;
my $output = "data";
my $out;
for (;;) {
print("Do you want to output to (S)creen or to (F)ile? ");
chomp( $out = uc( <STDIN> ) );
last if $out eq 'S' or $out eq 'F';
print("Invalid input. Please type either S or F.\n");
}
if ($out eq 'S') {
print $output;
}
else # $out eq 'F'
{
for (;;) {
print("Please enter filename: ");
chomp( my $save = <STDIN> );
if ( $save !~ /^[a-zA-Z][a-zA-Z_0-9]*\Z/ ) {
print("Invalid input. Please begin with a letter and do no
+t add extension, it will be added automatically.\n");
redo;
}
$save .= ".ext"; # XXX TODO
if ( -e $save ) {
my $overwrite;
for (;;) {
print("Filename exists. Overwrite? (Y) or (N) ");
chomp( $overwrite = uc( <STDIN> ) );
last if $overwrite eq 'Y' or $overwrite eq 'N';
print("Invalid input. Please type either Y or N.\n")
}
redo if $overwrite eq 'N';
}
open( my $fh_out, '>', $save )
or die "Unable to create $save: $!\n";
print $fh_out $output;
last;
}
}
Update: Added the the last last. I knew I needed it!
Update: Fixed the issues raised in replies to this node.
| [reply] [d/l] [select] |
|
|
i get the error:
"syntax error at output.pl line 3, at EOF
Execution of output.pl aborted due to compilation errors."
when i run the code above. any ideas why?
also, for some reason warning isnt in my distribution of perl. if i include use warning it comes up with the error:
"Can't locate warning.pm in @INC (@INC contains: /System/Library/Perl/5.8.6/darwin-thread-multi-2level /System/Library/Perl/5.8.6 /Library/Perl/5.8.6/darwin-thread-multi-2level /Library/Perl/5.8.6 /Library/Perl /Network/Library/Perl/5.8.6/darwin-thread-multi-2level /Network/Library/Perl/5.8.6 /Network/Library/Perl /System/Library/Perl/Extras/5.8.6/darwin-thread-multi-2level /System/Library/Perl/Extras/5.8.6 /Library/Perl/5.8.1/darwin-thread-multi-2level /Library/Perl/5.8.1 .) at output.pl line 3.
BEGIN failed--compilation aborted at output.pl line 3."
thanks for the help!
| [reply] |
|
|
| [reply] [d/l] |
|
|
|
|
|
|
|
|
Re: returning to a loop later on
by mreece (Friar) on Sep 07, 2006 at 00:30 UTC
|
if ($overwrite =~ (m^/[nN]{1}$/))
m^ suggests that ^ is the delimiter. you probably mean m/^[nN]{1}$/
| [reply] [d/l] [select] |
|
|
yes, you're right there was a typo. that fixed that part of the code but now, the code doesnt do what i want it to do.
basically,
there is some data that the user can either output to a file or the the screen.
the screen bit is easy.
then the user chooses a filename and that filename is checked for validity. that filename is then appended with the extension ".txt" and then it is checked to see if that exists. if it does exist then the user can either overwrite it or go back to the original loop of asking for the desired filename to be written.
im completely stuck. i guess i should be doing some sort of subroutining or something but i dont know the first thing about them!!! please help!
| [reply] |
|
|
without commenting on the sanity of this approach in general (ie, obligatory mention of IO::Prompt), here are some comments about this particular code:
1. always use strict;
2 (related). declare your variables in the appropriate scope
3. your code always prints "Invalid input" even when it is valid -- you want to print that only if they have typed something already.
4. you 'redo FILENAME' without resetting $save, so your while ($save !~ ...) fails the second time through
5. your open/print/close is within the if (-e $save) block, so it never happens if the file does not already exist
6. the {1} in your regular-expressions is useless, since 1 is the default.
7. you could use m/^[SF]$/i to match case-insensitively (/i means ignore-case), but i won't bother with that in the code below..
here is a revised version. i have tried to change as little as possible to make it work, so you can learn from your mistakes rather than be confronted with entirely new/unfamiliar code.
use strict;
my $output = "here is some output\n"; # for testing.. your output can
+ come from whereever
my $out;
while ( $out !~ m/^[sSfF]$/ ) {
print("\nInvalid input.\n Please type either S or F.\n")
if $out;
print("Do you want to output to (S)creen or to (F)ile?\n");
chomp( $out = <STDIN> );
}
if ( $out =~ m/^[sS]$/ ) {
print $output;
} elsif ( $out =~ m/^[fF]$/ ) {
my $save; # this is outside the FILENAME:{} block because it is
+needed at the end
FILENAME: {
while ( $save !~ (m/^[a-zA-Z][a-zA-Z_0-9]*$/) ) {
print("\nInvalid input.\n Please begin with a letter and d
+o not add extension, it will be added automatically.\n")
if $save;
print("Please enter filename:\n");
chomp( $save = <STDIN> );
}
if ( -e $save ) {
my $overwrite;
while ( $overwrite !~ (m/^[nNyY]$/) ) {
print("\nInvalid input.\n Please type either Y or N.\n
+")
if $overwrite;
print("\nFilename exists. Overwrite? (Y) or (N)\n");
chomp( $overwrite = <STDIN> );
}
if ( $overwrite =~ (m/^[nN]$/) ) {
undef $save; # reset $save to trigger new prompt!
redo FILENAME;
}
}
}
open( DATA, ">$save" ) || die "Couldn't open $save for writing: $!
+\n";
print DATA $output;
close(DATA);
}
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
while (...cond...) {
...body...
}
with
do {
...body...
} while (...cond...);
| [reply] [d/l] [select] |
Re: returning to a loop later on
by GrandFather (Saint) on Sep 07, 2006 at 02:27 UTC
|
{1} is redundant in a regex - always.
Your indentation is stuffed. It looks like the first if is inside the first while loop - it isn't.
redo FILENAME doesn't have a matching loop.
You could structure your code something like:
while (1) {
while ($out !~ m/^[sSfF]$/) {
...
}
if ($out =~ m/^[sS]$/) {
print $output;
next;
}
last;
}
exit if $out !~ m/^[fF]$/;
while (1) {
while ($save !~ (m/^[a-zA-Z]\w*$/)) {
...
}
if (-e $save) {
...
}
if ($overwrite =~ m/^[nN]$/) {
next;
}
...
last;
}
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
|
redo FILENAME doesn't have a matching loop.
it doesn't have to be a loop, you can label blocks, too!
my $i = 0;
FOO: {
print "$i\n";
redo FOO unless ++$i > 4;
}
| [reply] [d/l] |
|
|
FOO: { # scope 1
{ # scope 2
redo FOO; # Ok
}
redo FOO; # Ok
}
{ # scope 3
redo FOO; # Illegal
}
Prints:
DWIM is Perl's answer to Gödel
| [reply] [d/l] [select] |
|
|
|
|