Wie führe ich eine Perl-Ersetzung für eine Zeichenfolge durch, während das Original beibehalten wird?

179

Was ist in Perl eine gute Möglichkeit, eine Ersetzung für eine Zeichenfolge mithilfe eines regulären Ausdrucks durchzuführen und den Wert in einer anderen Variablen zu speichern, ohne das Original zu ändern?

Normalerweise kopiere ich die Zeichenfolge einfach in eine neue Variable und binde sie dann an den s///regulären Ausdruck, der die neue Zeichenfolge ersetzt. Ich habe mich jedoch gefragt, ob es einen besseren Weg gibt, dies zu tun.

$newstring = $oldstring;
$newstring =~ s/foo/bar/g;
Kaybenleroll
quelle

Antworten:

256

Dies ist die Redewendung, mit der ich immer eine modifizierte Kopie eines Strings erhalten habe, ohne das Original zu ändern:

(my $newstring = $oldstring) =~ s/foo/bar/g;

In Perl 5.14.0 oder höher können Sie den neuen /r zerstörungsfreien Substitutionsmodifikator verwenden :

my $newstring = $oldstring =~ s/foo/bar/gr; 

Hinweis: Die oben genannten Lösungen funktionieren auch ohne g. Sie funktionieren auch mit anderen Modifikatoren.

John Siracusa
quelle
6
Ob unter Verwendung streng oder nicht. Minimaler Umfang der Variablen ++
ysth
Ich habe mich gefragt, ob so etwas my $new = $_ for $old =~ s/foo/bar;funktionieren würde.
Benoit
2
@ Benoit, ich glaube du meinst s/foo/bar/ for my $newstring = $oldstring;es funktioniert, aber es ist viel seltsamer.
Ikegami
43

Die Aussage:

(my $newstring = $oldstring) =~ s/foo/bar/g;

Welches ist gleichbedeutend mit:

my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

Alternativ können Sie ab Perl 5.13.2 /reine zerstörungsfreie Substitution durchführen:

use 5.013;
#...
my $newstring = $oldstring =~ s/foo/bar/gr;
Klopfen
quelle
3
Hast du das gin deiner Top-Regex vergessen ?
Mareoraft
23

Unter use strictsagen wir:

(my $new = $original) =~ s/foo/bar/;

stattdessen.

Sam Kington
quelle
10

Die Einzeilerlösung ist als Shibboleth nützlicher als guter Code. Gute Perl-Codierer werden es wissen und verstehen, aber es ist viel weniger transparent und lesbar als das zweizeilige Couplet zum Kopieren und Ändern, mit dem Sie beginnen.

Mit anderen Worten, ein guter Weg, dies zu tun, ist die Art und Weise, wie Sie es bereits tun. Unnötige Präzision auf Kosten der Lesbarkeit ist kein Gewinn.

Josh Millard
quelle
Ah, aber die einzeilige Version unterliegt nicht dem Fehler bei der unbeabsichtigten Änderung der falschen Zeichenfolge.
ysth
Die einzeilige Version <i> ist bei korrekter Ausführung </ i> nicht Betreff, true. Aber das ist ein separates Thema.
Josh Millard
9
Sie denken vielleicht, es ist unnötig präzise, ​​aber wenn Sie einen Variablennamen zweimal eingeben müssen, um ihn einmal zu verwenden, ist die Anzahl der Fehlerpunkte doppelt so hoch. Es ist perfekt lesbar für Leute, die die Sprache kennen, und es ist sogar in unserem <i> Learning Perl </ i> -Kurs.
Brian D Foy
1

Eine weitere Lösung vor 5.14 : http://www.perlmonks.org/?node_id=346719 (siehe Japhys Beitrag)

Wie sein Ansatz verwendet map, funktioniert es auch gut für Arrays, erfordert jedoch eine Kaskadierung map, um ein temporäres Array zu erzeugen (andernfalls würde das Original geändert):

my @orig = ('this', 'this sucks', 'what is this?');
my @list = map { s/this/that/; $_ } map { $_ } @orig;
# @orig unmodified
textral
quelle
1

Ich hasse Foo und Bar. Wer hat sich diese unbeschreiblichen Begriffe in der Programmierung überhaupt ausgedacht?

my $oldstring = "replace donotreplace replace donotreplace replace donotreplace";

my $newstring = $oldstring;
$newstring =~ s/replace/newword/g; # inplace replacement

print $newstring;
%: newword donotreplace newword donotreplace newword donotreplace
JoGotta
quelle
2
Wie unterscheidet sich das vom Original? (Und ich denke, Sie wollen =~ s.)
Teepeemm
Clbuttic Fehler. Die tatsächliche Ausgabe dieses Codes istnewword donotnewword newword donotnewword newword donotnewword
Pascal
2
Sehen Sie ... wenn JoGotta das Traditionelle und Vertraute benutzt hätte foound bar, wäre seine Antwort richtig gewesen. Wieder einmal zu beweisen, dass Bräuche aus einem bestimmten Grund existieren und Lehren nur auf die harte Tour gezogen werden. ;)
Jon
-1

Wenn Sie Perl mit schreiben use strict;, werden Sie feststellen, dass die einzeilige Syntax auch dann nicht gültig ist, wenn sie deklariert ist.

Mit:

my ($newstring = $oldstring) =~ s/foo/bar/;

Du erhältst:

Can't declare scalar assignment in "my" at script.pl line 7, near ") =~"
Execution of script.pl aborted due to compilation errors.

Stattdessen ist die Syntax, die Sie verwendet haben, eine Zeile länger, aber die syntaktisch korrekte Methode, um dies zu tun use strict;. Für mich ist das Verwenden use strict;jetzt nur noch eine Gewohnheit. Ich mache es automatisch. Jeder sollte.

#!/usr/bin/env perl -wT

use strict;

my $oldstring = "foo one foo two foo three";
my $newstring = $oldstring;
$newstring =~ s/foo/bar/g;

print "$oldstring","\n";
print "$newstring","\n";
Tim Kennedy
quelle
1
Wenn Sie use warnings;stattdessen -w, erhalten Sie eine bessere Kontrolle: Zum Beispiel, wenn Sie Warnungen in einem Codeblock vorübergehend deaktivieren möchten.
Glenn Jackman