2010-12-18 16 views
2

Ich versuche, mich Perl beizubringen, und ich habe überall nach einer Antwort auf, was wahrscheinlich ein sehr einfaches Problem ist. Ich habe ein Unterprogramm definiert, das ich anrufe, um die Anzahl der Buchstaben in einem Wort zu zählen. Wenn ich es so schreibe:Anfänger rufen ein Perl-Unterprogramm

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

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

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

Dann funktioniert es wie ein Charme. Wenn ich es jedoch in eine Subroutine einpacke, teilt Split die Eingabe nicht auf und zählt stattdessen den ganzen Satz als eine einzelne Eingabe. Hier ist, wie ich die Definition der Unterprogramm:

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

Von allen Seiten, die ich gelesen habe und Texte, die ich konsultiert habe dies funktionieren sollte, aber es funktioniert nicht.

Vielen Dank im Voraus!

+5

Das Beste, was Sie sofort tun können, um das Lernen von Perl zu fördern ist * immer * enthalten 'Verwendung streng; Verwenden Sie Warnungen; 'am Anfang jeder Datei. – Ether

Antwort

13

Das Problem ist Ihre Verwendung von @_. Dies ist ein Array, aber Sie greifen darauf wie ein Skalar zu.

@_ enthält alle Parameter für diese Funktion. So wie es aussieht, gibst du ihm einen Satz, und du willst es teilen. Hier sind einige Möglichkeiten, es zu tun:

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

, die „die erste Parameter an die Funktion und teilen Sie es“ bedeutet.

Oder:

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

die so ziemlich das gleiche, aber verwendet eine Zwischengröße zur besseren Lesbarkeit.


In der Tat, was Sie tun, ist:

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

Was bedeutet:

  • interpretieren @_ als Skalar, was bedeutet, die Anzahl von Elementen in @_ (1, in diesem Fall)
  • teilen Sie die Zeichenfolge "1" von whitespa ce

, die das Array zurück:

@words = ("1"); 
+0

D'oh! Das macht Sinn, ich schätze die Aufklärung sehr. –

3

Sie den Hauptteil der Antwort von Nathan haben; Die restliche Beobachtung ist, dass die meisten Leute Interpunktion und Ziffern nicht als Buchstaben zählen, aber Ihr Unterprogramm tut es. Ich würde wahrscheinlich gehen mit:

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

Der entscheidende Punkt ist hier die Klammern um die Variablenliste in der my Klausel. Im Allgemeinen haben Sie mehrere Argumente in eine Unterübergeben, und Sie können zuweisen (Kopien) von ihnen zu Variablen in der Unterprogramm wie folgt aus:

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

Die Klammern bieten Liste Kontext "und stellen Sie sicher, dass das erste Element @_ wird nach $var1 kopiert, die zweite nach $var2 und so weiter.Ohne die Klammern haben Sie einen Skalarkontext. Wenn ein Array im Skalarkontext ausgewertet wird, entspricht der zurückgegebene Wert der Anzahl der Elemente im Array. Somit gilt:

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

würde wahrscheinlich zuweisen 3-$var1 (weil drei Werte wurden an die Subroutine übergeben) und $var1 und $var2 würden beide undef sein.

Der reguläre Ausdruck löscht alle nicht alphabetischen Zeichen aus der Zeichenfolge. die Anzahl der Buchstaben ist die Länge dessen, was übrig ist.

0

Beim Zählen von Zeichen ist der Transliterationsoperator von Perl oft nützlich. Um die Nicht-Leerzeichen zu zählen, ohne dass die Zeichenfolge in einzelne Wörter spalten, können Sie tun:

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