Perl Kleines Problem mit Perl RegEx

Chillosoph

Ensign
Registriert
Juli 2010
Beiträge
139
Hallo zusammen,

trotz intensiven Probierens stehe ich nun vor einem Problem bei dem ich keine Idee mehr hab.
Es geht darum, Vornamen aus einer Datei einzulesen, den einzelnen Buchstaben ihre numerischen Werte zuzuordnen und anschließend aufzusummieren. Nachstehend mal mein Lösungsansatz:

Code:
while(<NAMES>) {
	
	my ($line) = $_;

        $sum += (($line =~ s/A//g) * 1);
        [...]
        $sum += (($line =~ s/Z//g) * 26);

        print "\n", $sum, "\n";

}

Mein Problem besteht nun darin, dass das Konstrukt
Code:
(($line =~ s/A//g) * 1)
einfach keine Zahl zurückgibt, sondern NaN. Ich habe auf der Suche nach der Lösung mehrere Foren durchforstet, leider ohne Erfolg.
Falls es wichtig ist: Als Editor verwende ich NP++ und als Compiler Strawberry Perl. OS ist Windows 7.

Ich bedanke mich im voraus für eure Hilfe!
Viele Grüße,
Chillosoph
 
Viel hab ich bisher noch nicht in Perl gemacht, aber meine Vermutung ist, dass die Ersetzungsroutine genau wie ein Match nur True oder False zurückliefert, und du einen Wahrheitswert nicht mit einer Zahl multiplizieren kannst (wie gesagt, nur eine Vermutung).
Versuchs mal hiermit:
Code:
while ($line =~ /[Z]/g) {
  $count += 26;
}

Das ganze musst du damit aber immer noch 26 mal (für jeden Buchstaben einmal) machen. Eine bessere Möglichkeit wäre da wahrscheinlich, wenn du bspw. die Buchstaben des Alphabets in einem Hash ihren Zahlenwerten zuordnest, dann mit /[a-z]/ matchst, und bei jedem Treffer den Wert des Buchstabens addierst.
 
Mh, 26 while-Schleifen kommt mir etwas ineffizient vor. Zu deiner Frage, ob die Ersetzungsroutine nur True oder False zurückgeben kann: In der Perl Dokumentation steht unter "Search and replace":
Regular expressions also play a big role in search and replace operations in Perl. Search and replace is accomplished with the s/// operator.
[...]
If there is a match, s/// returns the number of substitutions made, otherwise it returns false.

Die Beispiele auf der Seite finde ich nicht sonderlich hilfreich, aber nach ein bisschen googeln habe ich Beispiele gefunden, die fast genau meiner Problematik entsprechen.

Mit Hash-Funktionen kenne ich mich überhaupt nicht aus, bin quasi noch blutiger Perl Anfänger. Ist das leicht zu implementieren?

Ich bedanke mich schonmal für deine Anregungen!
Schönen Abend,
Chillosoph
 
Meinst du in etwa das?

Code:
my $sum = 0;
while(<NAMES>) {	
	chomp;
	my @zeichen = split(//, uc($_));
	map { $sum += 1+ord($_)-ord('A'); } @zeichen;
        print "\n".$sum."\n";
}
 
Convexus, könntest du deinen Quellcode bitte ein wenig erläutern?
Wie gesagt, ich bin noch ziemlicher Anfänger und bin mit deinem Lösungsvorschlag ein wenig überfordert...
Hättest du außerdem eventuell noch einen Tipp, weshalb meine Idee nicht zum Ziel führt?
Danke im voraus!
 
Ich habe den Source mit Kommentaren versehen.

Code:
my $sum = 0;
while(<NAMES>) {	
       # newline am Ende der Zeile entfernen
	chomp; 

        # Zeichen nach Grossschrift mittels uc = uppercase
        # und Zeichenkette in Array wandeln
        # Bsp: 'abc\n' -> 'abc' [chomp] -> 'ABC' [uc] -> ('A', 'B', 'C') [split]

	my @zeichen = split(//, uc($_));

        # map fuehrt fuer jedes Element des Arrays @zeichen 
        # den Block in geschweiften Klammern aus
        # Hierbei enthaelt $_ das aktuelle betrachtete Element
        # ord() liefert den ASCII-Zeichencode eines Zeichen ord('A') = 65
	map { $sum += 1+ord($_)-ord('A'); } @zeichen;
        print "\n".$sum."\n";
}

Dein Ausdruck funktioniert im skalaren Kontext wie du es erwartest. Imo ist der Ausdruck allerdings schwer zu verstehen und entspricht nicht dem KISS (keep it simple stupid) welches insbesondere Anfaenger beherzigen sollten.


Prinzip.
Code:
  scalar($line =~ s/A//g) * 1
 
Was soll ich sagen, dein Lösungsvorschlag ist äußerst beeindruckend :)
Vielen Dank dafür!

(Hoffentlich) letzte Frage: Was meinst du mit "es funktioniert im skalaren Kontext"? Auch wenn ich das Schlüsselwort "scalar" vor den Ausdruck setzte, gibt er dennoch keine Zahl zurück.

Danke nochmal für deine aufschlussreiche Hilfe!
 
Vielen Dank für das Lob!

Ich habe nochmals in die Perl-Doku geschaut und demnach liefert der s///g - Befehl die Anzahl der Ersetzungen. Die Erzwingung des skalaren Kontextes ist nicht erforderlich, zumindest wenn die Anzahl der Ersetzungen >0 ist. Falls keine Ersetzung durchgeführt wurde, steht in der Doku das die leere Zeichenkette als Ergebnis ermittelt wird. Das könnte imo Probleme verursachen. Wenn du diesen Fall noch berücksichtigt, sollte es funktionieren.

Code:
   # $_ enthaelt Zeile
   $sum += (m/A/ ? s/A//g : 0);
 
Stimmt, ich habe in meinem Programm nochmal ein paar Zeilen geändert, sodass noch an anderen Zwischenergebnisse ausgegeben werden. NaN bekomme ich erst, wenn der Ausdruck keinen Treffer liefert.
Nun muss ich nur noch deinen Vorschlag verstehen, und Eulerproblem 22 steht nix mehr im Wege :)
Herzlichen Dank für deine leichtverständliche Hilfe!
 
Zurück
Oben