2010-07-25 56 views
9

有沒有辦法用內聯正則表達式替換文本,而不是從變量中取文本並將其存儲在變量中?Perl中的行內正則表達式替換

我是一個perl初學者。我經常發現自己寫

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

,我真的很想寫

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

或類似的,而不是使用一個臨時變量和三行。

有沒有辦法做到這一點?顯然,當正則表達式足夠複雜時,將其分開是有意義的,因此可以更好地解釋它,但是當它僅僅是s/\s//g時,感覺錯誤的是將代碼與其他變量混淆。

+1

愚弄http://stackoverflow.com/questions/3321400/how-to-do-perl-inline-regex-without-setting-to-a-變量 – daxim 2010-07-26 04:26:02

回答

2

可以使用do { }塊,以避免在當前範圍內創建一個臨時變量:

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

顯然,我想要的是不可能沒有混亂或我自己的功能。 (編寫它很容易,但是這使得其他人更難以掃描 - 他們不知道我的函數的語義。) – Charles 2010-07-25 21:02:34

+3

整個想法是澄清結果。做你正在顯示的內容仍然使用一個臨時變量'$ foo',並使程序更難理解。 我相信海報真正想做的事情是避免創建一個臨時的'$ foo'來執行doStuff函數。 – 2010-07-25 21:24:53

0

這是你想要什麼?:

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

打印:

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

通過將替換的定義放在一起可以節省一條線,但仍然使用臨時線。這是不可能的嗎? – Charles 2010-07-25 20:59:46

14

你真的不能做你想做的事,因爲替代函數返回一個1如果它工作,或者如果它沒有工作,則爲空字符串。這意味着,如果你這樣做:

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

doStuff功能將使用兩種1或空字符串作爲參數。沒有理由爲什麼替換函數不能返回結果字符串,而不是隻有1,如果它的工作。然而,這是Perl早期的設計決定。否則,這會發生什麼?

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

生成的字符串仍然是widget,但替換實際上失敗了。但是,如果替換返回結果字符串而不是空字符串,那麼if仍然是true。

然後,考慮這種情況下:

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

$bar現在是一個空字符串。如果替換返回結果,它將返回一個空字符串。然而,替換實際上成功了,我想我的if是真實的。

在大多數語言中,替代函數返回生成的字符串,你必須做這樣的事情:

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

如此,因爲一個Perl的設計決定的(基本上以更好地模擬awk語法) ,沒有簡單的方法去做你想做的事。然而,你可以這樣做:

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

這將在$foo地點的設置做一個不首先分配給它的$bar值。 $bar將保持不變。

+0

多麼令人失望。感謝您的非常完整的答案。 – Charles 2010-07-25 21:42:12

+2

從技術上講,///'返回所做的替換次數(如果是0,則返回空字符串)。但是如果你不使用'/ g',顯然不能超過1. – cjm 2010-07-26 00:52:12

+2

從理論上講,你可以爲'///'指定一個修飾符來告訴它創建一個字符串的副本, )修改副本,並返回新的字符串。我想我已經看到過之前提出的建議,但它還沒有(但是)將它製作成Perl,而且它可能永遠不會被添加。 – cjm 2010-07-26 00:56:25

-1

還有另一種方式:寫自己的函數:

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

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

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

這不會是值得的單呼,它很可能只是使你的代碼在這種情況下,更多的混亂。但是,如果你這樣做了十幾次,編寫自己的函數來做到這一點可能更有意義。

5
use Algorithm::Loops "Filter"; 

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

'List :: MoreUtils'具有相同的名爲'apply'的函數,這可能是一個更好的名字。 'Filter'使我想到'grep'類型的功能(可能是因爲'grep'在大多數語言中被稱爲'filter')。 – 2010-07-26 20:44:59