2009-04-11 11 views
4

das ich habe Probleme mit einer Funktion, die ich schrieb ...Warum funktioniert meine Perl-Funktion nicht?

sub TemplateReplace 
{ 
    my($regex, $replacement, $text) = @_; 
    $text =~ s/($regex)/($replacement)/gs; 
} 

my $text = "This is a test."; 
TemplateReplace("test", "banana", $text); 

Aber es funktioniert nicht. Ich dachte, Argumente wurden per Verweis in Perl gesendet. Wird die Zeile my($regex, $replacement, $text) = @_; dann kopiert? Wie behebe ich das?

+1

Bevor wir herausfinden, wie es zu beheben ist, müssen Sie erklären, was Sie wollen. Möchten Sie die ursprüngliche Variable ändern oder eine neue Zeichenfolge abrufen, die die Änderungen anzeigt? Es ist der Unterschied zwischen Chas. und Adnans Antworten. :) –

+0

Wenn Sie versuchen, das übergebene Argument magisch zu bearbeiten, dann ist die Antwort von Chas diejenige, nach der Sie suchen. Wenn du lieber den "richtigen Weg" machst, folge Adnans. Das Ändern von Variablen aus der Ferne ist im Allgemeinen verpönt, es erhöht normalerweise nur die Komplexität mit wenig Nutzen. – Danny

Antwort

8

Sie ändern eine Kopie der $text Sie bestanden in; Dies hat keine Auswirkungen auf das Original.

#!/usr/bin/perl 

use strict; 
use warnings; 

my $text = "This is a test."; 

template_replace(qr/test/, "bannana", $text); 

print "$text\n"; 

sub template_replace { 
    my $regex  = shift; 
    my $replacement = shift; 
    $_[0] =~ s/$regex/$replacement/gs; 
} 

Der Code funktioniert oben, weil die Elemente von @_ zu den übergebenen Variablen aliased sind. Aber Adnan ‚s Antwort die häufiger geschehen ist. Das Modifizieren von Argumenten, die in Funktionen übergeben werden, ist ein überraschendes Verhalten und lässt Dinge wie template_replace(qr/foo/, "bar", "foo is foo") nicht funktionieren.

10
sub TemplateReplace 
{ 
    my($regex, $replacement, $text) = @_; 
    $text =~ s/($regex)/($replacement)/gs; 
    return $text; 
} 

my $text = "This is a test."; 
$text = TemplateReplace("test", "banana", $text); 

Dort. Das sollte funktionieren.

Und ja, Ihr my (..) = @_ kopiert die Argumente. Wenn Sie also eine Variable ändern, müssen Sie sie zurückgeben, es sei denn, sie ist global.

+0

+1 für eine korrekte Methode, obwohl Chas. Owens 'Antwort hat mir geholfen, mehr zu verstehen. – rlbond

4

Es ist die "Zuweisung" Teil der Unterroutine, die die Kopien der Daten macht.

Wenn Sie die @_ Argumente direkt ändern, funktionieren sie wie erwartet. Es ist jedoch nicht sehr gut lesbar. :-)

use strict; 
umask(0); 
$|=1; 
my $debug = 0; 

my $text = "This is a test."; 

print "Before 1: [$text]\n"; 
TemplateReplace("test", "banana", $text); 
print "After 1: [$text]\n"; 

print "Before 2: [$text]\n"; 
TemplateReplace2("test", "banana", $text); 
print "After 2: [$text]\n"; 

sub TemplateReplace 
    { 
    my ($regex, $replacement, $text) = @_;  

    $text =~ s/($regex)/($replacement)/gs; 
    } 

sub TemplateReplace2 
    { 
    $_[2] =~ s/$_[0]/$_[1]/gs; 
    } 

kehrt:

Before 1: [This is a test.] 
After 1: [This is a test.] 
Before 2: [This is a test.] 
After 2: [This is a banana.] 
0

Hier ist eine Variation, wie es zu tun ist, die fast identisch mit Ihrem Code mit einem kleinen Unterschied ist.

use strict; 
use warnings; 


sub TemplateReplace { 
    my($regex, $replacement, $text) = @_; 
    $$text =~ s/($regex)/$replacement/gs; 
} 



my $text = "This is a test."; 
TemplateReplace("test", "banana", \$text); 
print $text; 

Dieses Verhalten ist explizite statt impliziten. In der Praxis funktioniert es identisch mit Chas. Owens result, verwendet aber skalare Referenzen, anstatt sich auf das Verhalten von Arrays zu verlassen.

Dies macht es für jeden lesender Code mehr offensichtlich, dass die Funktion "TemplateReplace" absichtlich modifizieren $ Text ist.

Darüber hinaus wird es Ihnen sagen, Sie verwenden es falsch, indem sie mit kreischend:

 
Can't use string ("This is a test.") as a SCALAR ref while "strict refs" in use at replace.pl line 9. 

Wenn Sie die \ irgendwo vergessen passieren.

Verwandte Themen