Warum gibt meine Perl-Map nichts zurück?
Frage
Wenn ich die folgende Anweisung ausführe:
@filtered = map {s/ //g} @outdata;
Es wird eine leere Liste anstelle der erwarteten gefilterten Liste zurückgegeben.Ich versuche, jedes Vorkommen von zu entfernen
aus einem String-Array (das eine XML-Datei ist).
Offensichtlich verstehe ich etwas nicht.Kann mir jemand sagen, wie das richtig gemacht werden könnte und warum das bei mir nicht so funktioniert, wie es ist?
Lösung
Versuche dies:
@filtered = map {s/ //g; $_} @outdata;
Das Problem besteht darin, dass der s-Operator in Perl $_ ändert, aber tatsächlich die Anzahl der vorgenommenen Änderungen zurückgibt.Das zusätzliche $_ am Ende bewirkt also, dass Perl die geänderte Zeichenfolge für jedes Element von @outdata zurückgibt.
Andere Tipps
Beachten Sie, dass „map“ auch Ihr Quellarray ändert.Sie können also entweder Folgendes tun:
map {s/ //g} @outdata;
und überspringen Sie die @filtered-Variable ganz, oder wenn Sie die Originale behalten müssen,
@filtered = @outdata;
map {s/ //g} @filtered;
Obwohl es in diesem Fall möglicherweise besser lesbar ist, foreach zu verwenden:
s/ //g foreach @filtered;
Gregs Antwort hat das Problem, dass das ursprüngliche Array geändert wird, wenn $_ als Alias übergeben werden.Du brauchst:
@filtered = map { (my $new = $_) =~ s/ //g; $new} @outdata;
Um Tithoniums Argument weiterzuverfolgen: Dies wird auch den Zweck erfüllen:
@filtered = map {local $_=$_; s/ //g; $_} @outdata;
„Lokal“ stellt sicher, dass Sie an einer Kopie und nicht am Original arbeiten.
In Perl 5.14 könnten Sie das verwenden /R Regex-Modifikator für Nehmen Sie eine zerstörungsfreie Substitution vor.
@filtered = map {s/ //gr} @outdata;
use Algorithm::Loops "Filter";
@filtered = Filter { s/ //g } @outdata;
Als Kontrapunkt zu Gregs Antwort könnten Sie grep missbrauchen:
@filtered = grep {s/ //g; 1} @outdata;
Tun Sie das nicht.