开发者

Beginner calling a Perl subroutine

I am trying to teach myself Perl and I've looked everywhere for an answer to what probably is a very simple problem. I've defined a subroutine that I call to count the number开发者_Python百科 of letters in a word. If I write it out like this:

 $sentence="This is a short sentence.";

 @words = split(/\s+/, $sentence);

 foreach $element (@words) {
     $lngths .= length($element) . "\n";
 }
 print "$lngths\n";

Then it works like a charm. However, if I wrap it into a subroutine split doesn't split up the input and instead counts the whole sentence as a single input. Here's how I'm defining the subroutine:

sub countWords {
    @words = split(/\s+/, @_);
    foreach $element(@words) {
        $lngths .= length($element) . "\n";
    }
    return $lngths;
}

From all the pages I've read and texts I've consulted this should work but it doesn't.

Thanks in advance!


The problem is your use of @_. This is an array, but you're accessing it like a scalar.

@_ contains all the parameters to this function. The way it looks, you're passing it a sentence, and you want to split it. Here are some possible ways to do it:

@words = split(/\s+/, $_[0]);

which means "take the first parameter to the function and split it".

Or:

my $sentence = shift;
@words = split(/\s+/, $sentence);

Which is pretty much the same, but uses an intermediate variable for readability.


In fact, what you're doing is:

@words = split(/\s+/, @_);

Which means:

  • interpret @_ as a scalar, which means the number of elements in @_ (1, in this case)
  • split the string "1" by whitespace

Which returns the array:

@words = ("1");


You've got the main part of the answer from Nathan; the residual observation is that most people don't count punctuation and digits as letters, but your subroutine does. I'd probably go with:

sub countLetters
{
    my($sentence) = @_;
    $sentence =~ s/[^[:alpha:]]//gm;
    return length($sentence);
}

The key point here is the parentheses around the variable list in the my clause. In general, you have several arguments passed into a sub, and you can assign (copies) of them to variables in your subroutine like this:

my($var1, $var2, $var3) = @_;

The parentheses provide 'list context' and ensure that the first element of @_ is copied to $var1, the second to $var2 and so on. Without the parentheses, you have 'scalar context', and when an array is evaluated in scalar context, the value returned is the number of elements in the array. Thus:

my $var1, $var2, $var3 = @_;

would likely assign 3 to $var1 (because three values were passed to the subroutine), and $var1 and $var2 would both be undef.

The regular expression deletes all non-alphabetic characters from the string; the number of letters is the length of what's left.


When counting characters, perl's transliteration operator often comes in handy. To count the non-whitespace characters without having to split your string into separate words, you can do:

$lngths = $sentence =~ tr/ \t\f\r\n//c;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜