2008-08-22 7 views
146

In Perl, was ist eine gute Möglichkeit, eine Ersetzung für eine Zeichenfolge mit einem regulären Ausdruck durchzuführen und den Wert in einer anderen Variablen zu speichern, ohne das Original zu ändern?Wie führe ich eine Perl-Substitution in einer Zeichenfolge aus, während das Original beibehalten wird?

Normalerweise kopiere ich die Zeichenfolge in eine neue Variable und binde sie dann an die s/// Regex, die den Ersatz für die neue Zeichenfolge tut, aber ich frage mich, ob es eine bessere Möglichkeit gibt, dies zu tun?

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

Antwort

203

Dies ist das Idiom ich eine modifizierte Kopie einer Zeichenfolge zu erhalten, ohne das Original zu verändern immer verwendet haben:

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

In Perl 5.14.0 oder später, können Sie die neue /r verwenden können non-destructive substitution modifier:

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

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

+5

Ob unter Verwendung streng oder nicht. Minimaler Gültigkeitsbereich der Variablen ++ – ysth

+0

Ich frage mich, ob etwas wie 'my $ new = $ _ für $ old = ~ s/foo/bar;' funktionieren würde? – Benoit

+1

@Benoit, ich glaube du meinst 's/foo/bar/für meine $ newstring = $ oldstring;' Es funktioniert, aber es ist weit seltsamer. – ikegami

41

Die Aussage:

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

entspricht:

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

Alternativ kann, wie von 5.13.2 Perl Sie /r verwenden können, eine nicht destruktive Substitution zu tun:

use 5.013; 
#... 
my $newstring = $oldstring =~ s/foo/bar/gr; 
+3

Hast du das 'g' in deinem Top-Regex vergessen? – mareoraft

-1

Wenn Sie Perl mit use strict; schreiben, dann finden Sie, dass die eine Zeile syn Steuer ist nicht gültig, auch wenn sie erklärt wird.

mit:

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

Sie erhalten:

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

Stattdessen wird die Syntax, die Sie verwendet haben, während eine Zeile länger, die syntaktisch korrekte Art und Weise ist es mit use strict; zu tun. Für mich ist die Verwendung von use strict; jetzt nur 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"; 
+0

Wenn Sie Warnungen anstelle von "-w" verwenden, erhalten Sie mehr Kontrolle: zum Beispiel, wenn Sie Warnungen in einem Codeblock vorübergehend ausschalten möchten. –

19

Unter use strict, sagen:

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

statt.

8

Die One-Liner-Lösung ist nützlicher als ein Shibboleth als guter Code; gute Perl-Codierer werden es wissen und verstehen, aber es ist viel weniger transparent und lesbar als das Zwei-Zeilen-Kopieren-und-Modifizieren-Paar, mit dem Sie beginnen.

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

+0

Ah, aber die Ein-Zeilen-Version unterliegt nicht dem Fehler in der Frage der unbeabsichtigten Änderung der falschen Zeichenfolge. – ysth

+0

Die One-Line-Version, , wenn korrekt ausgeführt, ist nicht Gegenstand, wahr. Aber das ist ein separates Problem. –

+7

Sie denken vielleicht, dass es unnötig ist, aber wenn Sie einen Variablennamen zweimal eingeben müssen, um ihn einmal zu verwenden, ist das doppelt so viele Fehlerpunkte. Es ist perfekt lesbar für Menschen, die die Sprache kennen, und es ist sogar in unserem Kurs Learning Perl. –

1

Ich hasse foo und bar .. wer hat sich diese nicht-beschreibenden Begriffe in der Programmierung sowieso 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 
+2

Wie unterscheidet sich das vom Original? (Und ich denke du willst '= ~ s'.) – Teepeemm

+0

Clbuttic Fehler. Die tatsächliche Ausgabe dieses Codes ist "newword donotnewword newword donotnewword newword donotnewword" – Pascal

0

Eine weitere vorge 5.14 Lösung: http://www.perlmonks.org/?node_id=346719

Als sein Ansatz nutzt map, es funktioniert gut auch für Arrays (Japhy den Beitrag sehen), aber map erfordert Kaskadierung ein temporäres Array zu erzeugen (sonst das Original würde geändert werden):

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