2010-07-25 9 views
9

Czy istnieje sposób na zastąpienie tekstu za pomocą wyrażenia regularnego, zamiast pobierania tekstu ze zmiennej i zapisywania jej w zmiennej?Zamiennik regex inline w perlu

Jestem początkującym początkującym. I często znajduję się pisać

my $foo = $bar; 
$foo =~ s/regex/replacement/; 
doStuff($foo) 

gdzie naprawdę chciałbym napisać

doStuff($bar->replace(s/regex/replacement/)); 

lub podobnego, zamiast zmiennej tymczasowej i trzy linie.

Czy istnieje sposób, aby to zrobić? Oczywiście, gdy wyrażenie regularne jest wystarczająco skomplikowane, ma sens podzielenie go, aby można go było lepiej wyjaśnić, ale gdy jest to tylko s/\s//g, źle jest zaśmiecać kod dodatkowymi zmiennymi.

+1

Dupes http://stackoverflow.com/questions/3321400/how-to-do-perl-inline-regex-without-setting-to-a- zmienna – daxim

Odpowiedz

2

Można użyć do { } blok, aby uniknąć tworzenia zmiennej tymczasowej w bieżącym zakresie:

doStuff(do {(my $foo = $bar) =~ s/regex/replacement/; $foo}); 
+0

Najwyraźniej to, czego chcę, nie jest możliwe bez bałaganu i mojej własnej funkcji. (Łatwo to napisać, ale to utrudnia innym skanowanie - nie znają semantyki mojej funkcji.) – Charles

+3

Cała idea polegała na wyjaśnieniu wyników. Robiąc to, co pokazujesz wciąż używa zmiennej tymczasowej '$ foo' i sprawia, że ​​program jest trudniejszy do zrozumienia. Wierzę w to, co naprawdę chciał zrobić plakat, to unikanie konieczności utworzenia tymczasowego '$ foo', które można umieścić w funkcji DoStuff. –

0

Czy to, co chcesz ?:

my $foo = 'Replace this with that'; 
(my $bar = $foo) =~ s/this/that/; 
print "Foo: $foo\nBar: $bar\n"; 

Wydruki:

Foo: Replace this with that 
Bar: Replace that with that 
+0

To zapisuje linię, umieszczając definicję razem z podstawieniem, ale nadal używa tymczasowego. Czy nie można tego uniknąć? – Charles

14

Naprawdę nie możesz zrobić tego, co chcesz, ponieważ funkcja podstawiania zwraca albo 1 jeśli zadziałał lub pusty ciąg znaków, jeśli nie działał. Oznacza to, że jeśli to zrobił:

doStuff($foo =~ s/regex/replacement/); 

Funkcja doStuff byłyby stosując albo 1 lub pusty łańcuch jako parametr. Nie ma powodu, dla którego funkcja substytucji nie mogłaby zwrócić wynikowego łańcucha zamiast tylko 1, gdyby zadziałał. Była to jednak decyzja projektowa od najwcześniejszych dni Perla. W przeciwnym razie, co by się z tym stało?

$foo = "widget"; 
if ($foo =~ s/red/blue/) { 
    print "We only sell blue stuff and not red stuff!\n"; 
} 

Wynikowy ciąg nadal jest widget, ale podstawienie faktycznie nie powiodło się. Jeśli jednak podstawienie zwróci wynikowy ciąg znaków, a nie pusty ciąg znaków, wartość if będzie nadal prawdziwa.

Następnie, należy rozważyć tę sprawę:

$bar = "FOO!"; 
if ($bar =~ s/FOO!//) { 
    print "Fixed up \'\$bar\'!\n"; 
} 

$bar jest teraz pusty. Jeśli podstawienie zwróci wynik, zwróci pusty ciąg znaków. Jednak zastąpienie faktycznie się udało i chcę, aby moja if była prawdziwa.

W większości języków, funkcja podstawienie zwraca wynikowy ciąg znaków, a trzeba by zrobić coś takiego:

if ($bar != replace("$bar", "/FOO!//")) { 
    print "Fixed up \'\$bar''!\n"; 
} 

tak, to z powodu decyzji projektowej Perl (zasadniczo lepiej naśladować składnia awk) nie ma łatwego sposobu robienia tego, co chcesz.Jednak można to zrobić w ten sposób:

($foo = $bar) =~ s/regex/replacement/; 
doStuff($foo); 

To byłoby zrobić w ustawieniach miejsce $foo bez uprzedniego przypisując mu wartość $bar. $bar pozostanie niezmieniony.

+0

Jak rozczarowujące. Dzięki za bardzo kompletną odpowiedź. – Charles

+2

Technicznie, 's ///' zwraca liczbę wykonanych podstawień (lub pusty łańcuch, jeśli jest to 0). Ale jeśli nie używasz '/ g', oczywiście to nie może być więcej niż 1. – cjm

+2

Teoretycznie możesz mieć modyfikator dla' s /// ', który mówi mu, aby utworzyć kopię ciągu, (być może) zmodyfikuj kopię i zwróć ten nowy ciąg. Wydaje mi się, że już wcześniej widziałem to, co sugerowałem, ale nie zostało (jeszcze) w Perlu i może nigdy nie zostać dodane. – cjm

-1

Jest jeszcze inny sposób: Napisz własną funkcję:

sub replace (
    my $variable = shift; 
    my $substring = shift; 

    eval "\$variable =~ s${substring};"; 
    return $variable 
} 

doStuff(replace($foo, "/regex/replace/")); 

to nie byłoby warto dla pojedynczego połączenia, i będzie to prawdopodobnie tylko uczynić kod bardziej kłopotliwe w tej sprawie. Jeśli jednak robisz to kilkanaście razy, może być sensownym pisanie własnej funkcji, aby to zrobić.

5
use Algorithm::Loops "Filter"; 

# leaves $foo unchanged 
doStuff(Filter { s/this/that/ } $foo); 
+0

'List :: MoreUtils' ma tę samą funkcję o nazwie' apply', która jest prawdopodobnie lepszą nazwą dla niego. "Filtr" sprawia, że ​​myślę o funkcji 'grep' (prawdopodobnie dlatego, że' grep' w większości języków jest nazywane 'filtrem'). –