2013-05-30 13 views
8

Gibt es eine Möglichkeit, mehrere Zeichenfolgen in einer Zeichenfolge zu ersetzen? Zum Beispiel habe ich die Zeichenfolge hello world what a lovely day und ich möchte sonst what und lovely mit etwas ersetzen ..Perl ersetzen mehrere Zeichenfolgen gleichzeitig

$sentence = "hello world what a lovely day"; 
@list = ("what", "lovely"); # strings to replace 
@replist = ("its", "bad"); # strings to replace with 
($val = $sentence) =~ "tr/@list/@replist/d"; 
print "$val\n"; # should print "hello world its a bad day".. 

Irgendwelche Ideen, warum funktioniert es nicht?

Danke.

+0

Werden die Wörter immer ganze Wörter sein oder gibt es das Potenzial für Muster? – squiguy

Antwort

9

Zunächst funktioniert tr nicht so; Für Einzelheiten siehe perldoc perlop, aber tr tut Transliteration und unterscheidet sich sehr von Substitution.

Zu diesem Zweck wird ein richtiger Weg wäre

# $val 
$val =~ s/what/its/g; 
$val =~ s/lovely/bad/g; 

Beachten Sie, dass „gleichzeitig“ Veränderung ist etwas schwieriger, aber wir könnten es tun, zum Beispiel,

%replacements = ("what" => "its", "lovely" => "bad"); 
($val = $sentence) =~ s/(@{[join "|", keys %replacements]})/$replacements{$1}/g; 

zu ersetzen sein (Es kann notwendig sein, Zeichenfolgen durch Metazeichen zu ersetzen.)

Dies ist immer noch nur gleichzeitig in einem sehr lockeren Sinn des Begriffs, aber es tut für die meisten Zwecke ac t als ob die Substitutionen in einem Durchgang durchgeführt werden.

Es ist auch korrekter, "what" durch "it's" statt "its" zu ersetzen.

6

Nun, hauptsächlich funktioniert es nicht als tr///d hat nichts mit Ihrer Anfrage zu tun (tr/abc/12/d ersetzt eine mit 1, b mit 2, und entfernt c). Außerdem interpolieren Arrays standardmäßig nicht in reguläre Ausdrücke auf eine Weise, die für Ihre Aufgabe nützlich ist. Ohne eine Hash-Abfrage oder einen Unterprogrammaufruf oder eine andere Logik können Sie auch keine Entscheidungen auf der rechten Seite einer s///-Operation treffen.

Um die Frage im Titel zu beantworten, können Sie gleichzeitig mehr ersetzt ausführen - äh, in bequemer Nachfolge - auf diese Weise:

#! /usr/bin/env perl 
use common::sense; 

my $sentence = "hello world what a lovely day"; 

for ($sentence) { 
    s/what/it's/; 
    s/lovely/bad/ 
} 

say $sentence; 

wie etwas mehr zu tun, was Sie hier versuchen:

#! /usr/bin/env perl 
use common::sense; 

my $sentence = "hello world what a lovely day"; 

my %replace = (
    what => "it's", 
    lovely => 'bad' 
); 

$sentence =~ s/(@{[join '|', map { quotemeta($_) } keys %replace]})/$replace{$1}/g; 

say $sentence; 

Wenn Sie eine Menge solcher Ersatz werde tun, 'kompilieren' die Regex zuerst:

my $matchkey = qr/@{[join '|', map { quotemeta($_) } keys %replace]}/; 

... 

$sentence =~ s/($matchkey)/$replace{$1}/g; 

EDIT:

Und auf meiner Bemerkung über Array-Interpolation zu erweitern, können Sie $" ändern:

local $" = '|'; 
$sentence =~ s/(@{[keys %replace]})/$replace{$1}/g; 
# --> $sentence =~ s/(what|lovely)/$replace{$1}/g; 

Welche Dinge hier nicht verbessern, wirklich, obwohl es kann, wenn Sie bereits die Schlüssel in einem haben Array:

local $" = '|'; 
$sentence =~ s/(@keys)/$replace{$1}/g; 
Verwandte Themen