1

Okay, so there is an input form, with 4 text boxes. I get the input using CGI.pm:

my $exc0 = param('exclude0') || 'a'; 
my $exc1 = param('exclude1') || 'a';
my $exc2 = param('exclude2') || 'a';
my $exc3 = param('exclude3') || 'a';

The reason I had to include the || 'a' is to allow it to work if there was no input. Is there a safer way to do this?

It gets called later on in a regex:

next if ($totalmatch->[2] =~ /\b$exc0\b/i);
next if ($totalmatch->[2] =~ /\b$exc1\b/i);
next if ($totalmatch->[2] =~ /\b$exc2\b/i);
next if ($totalmatch->[2] =~ /\b$exc3\b/i);

Where $totalmatch->[2] is a sentence. If I don't check for no input, when there isn't an input no matches come up (a.k.a. it includes $exc in every case). I'd guess this is because there is an undef or space in every sentence?

What I've tried is || '' and I suppose I could use a if ($exc0) or a if defined() or eq '' but just looking for help.

Thanks a lot for your time.

Jon
  • 757
  • 5
  • 20
  • 1
    I can't speak to safer as I don't see safety as the issue. But there is certainly an easier way. Anytime you see yourself typing "$variable_number", as in "$exc0", you should be asking is this a job better suited to an array? `my @exc = map { param( "exclude$_" ) || 'a' } 0 .. 3;` ....and later... `foreach ( @exc ) { next if ( $totalmatch->[2] =~ /\b$exc[$_]\b/i ); .... }` – DavidO Jun 28 '11 at 18:15
  • Sorry for the unclarity. 'a' might be in the sentence, which I don't want to exclude. Great way to short the code, and thanks for the general tips. Still haven't gotten used to using map on a regular basis. THANKS! – Jon Jun 28 '11 at 18:19
  • Wait... is map just a for loop rewritten? – Jon Jun 28 '11 at 18:21
  • Think of it as a for loop that spits out a list. It's documented in `perldoc -f map`. It's similar to `my @array; for ( list ) { push @array, something }` (pseudo-code) – DavidO Jun 28 '11 at 18:29
  • 1
    undef in a string-context, like in a regex, acts as if it was an empty string. *Every* string contains the empty string, so every string will match a regex that matches the empty string. – tadmc Jun 28 '11 at 18:30
  • Ah, thanks a lot for all your help. Cleared it up for me (both DavidO and tadmc). – Jon Jun 28 '11 at 18:32
  • 1
    Are `exclude0`, etc regex patterns? If not, you want `/\b\Q$exc0\E\b/` – ikegami Jun 29 '11 at 00:38
  • You've got problems if they enter `!`, as it won't work the way you want with `\b` – ikegami Jun 29 '11 at 00:39
  • `|| 'a'` will change an input of `0` to `a`. I suspect that's not desirable. – ikegami Jun 29 '11 at 00:40
  • 1
    @tadmc, but every string will not match `/\b\b/`. In fact, none will. – ikegami Jun 29 '11 at 00:45
  • Wow, thank you ikegami for your wise deduction. You caught things I never would have thought of! Hopefully, experience will help me in the future! – Jon Jun 29 '11 at 03:11

1 Answers1

3

If you don't do use warnings and don't do the || 'a' you should get a warnings: Use of uninitialized value at ...

It's best practice in perl (or any language, for that matter) to check for the existence of a variable before you use it in a function, or in this case, a regular expression, unless there is a specific reasons of it being null being a desirable possibility.

Your should really get rid of the || 'a' and do this:

next if (length($exc0) and $totalmatch->[2] =~ /\b$exc0\b/i);
next if (length($exc1) and $totalmatch->[2] =~ /\b$exc1\b/i);
next if (length($exc2) and $totalmatch->[2] =~ /\b$exc2\b/i);
next if (length($exc3) and $totalmatch->[2] =~ /\b$exc3\b/i);

You don't want to use defined() here because '' is defined, and you'll still have the problem of it matching.

Corey Henderson
  • 7,239
  • 1
  • 39
  • 43
  • Thanks, that does the job. I thought -w on the hash-bang line was the same as use warnings? Is && faster/more efficient than "and"? Thanks a lot! – Jon Jun 28 '11 at 18:15
  • 2
    If $exc0 et. al. might ever have a value of '0' then Corey's code will not do the right thing. Since we want to check that the variable has some length before we use it, we should be doing: next if (length($exc0) and $totalmatch->[2] ... – tadmc Jun 28 '11 at 18:33
  • @Jon, You would also get the warning with `-w`, but `-w` and `use warnings;` are not the same. `use warnings;` is lexically scoped, while `-w` is global. – ikegami Jun 29 '11 at 00:42
  • @Jon, there no difference in efficiency between `&&` and `and`. The difference is in operator precedence. That affects how code is parsed. In this case, `&&` is the conventional choice, but `and` will behave identically. – ikegami Jun 29 '11 at 00:44
  • 1
    @Corey Henderson, @Jon, In order to avoid a warning, `length($exc0)` should be `length($exc0 // '')` if the code will run on Perl 5.10. If the code will run on Perl 5.8, `defined($exc0) && length($exc0)` is needed to avoid the warning. – ikegami Jun 29 '11 at 00:49