2013-05-30 25 views
8

Czy istnieje sposób na zastąpienie wielu ciągów w ciągu znaków? Na przykład, mam ciąg hello world what a lovely day i chcę zastąpić what i lovely coś innego ..Perl zastępuje wiele ciągów jednocześnie.

$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".. 

pomysłów, dlaczego to nie działa?

Dzięki.

+0

Czy słowa będą zawsze całymi słowami, czy też istnieje potencjał wzorców? – squiguy

Odpowiedz

9

Po pierwsze, tr nie działa w ten sposób; skonsultuj się z perldoc perlop, aby uzyskać szczegółowe informacje, ale tr robi transliterację i bardzo różni się od podstawienia.

W tym celu bardziej poprawny sposób zastąpić byłoby

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

Zauważ, że „jednoczesne” zmiana jest raczej trudne, ale możemy to zrobić, na przykład,

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

(Ewentualnie może być konieczne wyzwolenie, aby zastąpić ciągi znakami metaznaków.)

Jest to nadal tylko symultaniczne w luźnym znaczeniu tego słowa, ale w większości tak, jakby podstawienia odbywały się w jednym przebiegu.

Ponadto lepiej zastąpić "what" przez "it's", a nie "its".

6

Cóż, głównie nie działa, ponieważ tr///d nie ma nic wspólnego z Twoją prośbą (tr/abc/12/d zastępuje a 1, bz 2 i usuwa c). Ponadto, domyślnie tablice nie interpolują się w wyrażenia regularne w sposób przydatny dla twojego zadania. Ponadto, bez czegoś takiego jak hash lub wywołanie podprogramu lub inna logika, nie możesz podejmować decyzji po prawej stronie operacji s///.

Aby odpowiedzieć na pytanie w tytule, można wykonywać wiele zostaje zastąpiony przez jednoczesne - er, w dogodnej rzędu - w ten sposób:

#! /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; 

zrobić coś więcej jak to, co próbują tutaj:

#! /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; 

Jeśli będziesz robił dużo takich zamienników „kompilacji” pierwszy regex:

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

... 

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

EDIT:

I rozszerzyć na moją uwagę o interpolację tablicy, można zmienić $":

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

Które nie poprawi rzeczy tutaj, naprawdę, choć może jeśli już klucze w sposób array:

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