2010-07-13 112 views
5

有沒有辦法在替換中使用變量作爲修飾符?如何在替換中使用變量作爲修飾符

my $search = 'looking'; 
my $replace = '"find: $1 ="'; 
my $modifier = 'ee'; 

s/$search/$replace/$modifier; 

我需要使用散列數組進行批量搜索 - 用不同的修飾符進行替換。

+9

某些修飾符可以在「正則表達式」中作爲'(?modifier:pattern)'提供,但不能影響整個事物,如/ g或/ e。這是「你爲什麼要這樣做」的時刻之一。如果你告訴我們這是爲了什麼,我們可能會想出一個更簡單的方法,而不是刷駱駝毛(並打開安全孔)。 – Schwern 2010-07-13 18:50:42

+0

@Schwern:如果你在駱駝上開一個洞,這是最讓人不愉快的事 – Borodin 2015-06-12 08:06:47

回答

3

嗯,如果我不得不這樣做,我會做這樣的:

use warnings; 
use strict; 
my @stuff = (
{ 
    search => "this", 
    replace => "that", 
    modifier => "g", 
}, 
{ 
    search => "ono", 
    replace => "wendy", 
    modifier => "i", 
} 
); 
$_ = "this ono boo this\n"; 
for my $h (@stuff) { 
    if ($h->{modifier} eq 'g') { 
     s/$h->{search}/$h->{replace}/g; 
    } elsif ($h->{modifier} eq 'i') { 
     s/$h->{search}/$h->{replace}/i; 
    } 
    # etc. 
} 
print; 

有你可能想我覺得這個用那麼只有這麼多不同的修飾符很簡單。

你可以使用eval這個,但它非常混亂。

+7

凌亂的眼睛是一個觀察者。我發現這比eval解決方案更混亂。 – runrig 2010-07-13 18:00:52

+2

@runrig:在這種情況下「雜亂」並不是指代碼的外觀。如果您使用'eval',則需要處理很多難以跟蹤的錯誤。 – 2010-07-14 00:36:37

+0

這是我在問Stackoverflox之前想到的解決方案。 – bem33 2010-07-14 02:07:50

4

如果您戴上安全護目鏡和零分服裝,則可以使用eval

如:

use strict; 
use warnings; 
sub mk_re { 
    my ($search, $replace, $modifier) = @_; 
    $modifier ||= ''; 
    die "Bad modifier $modifier" unless $modifier =~ /^[msixge]*$/; 
    my $sub = eval "sub { s/($search)/$replace/$modifier; }"; 
    die "Error making regex for [$search][$replace][$modifier]: [email protected]" unless $sub; 
    return $sub; 
} 

my $search = 'looking'; 
my $replace = '"find: $1 ="'; 
my $modifier = 'e'; 

# Sub can be stored in an array or hash 
my $sub = mk_re($search, $replace, $modifier); 

$_ = "abc-looking-def"; 
print "$_\n"; 
$sub->(); 
print "$_\n"; 
+0

我的零分錢套裝在它的無窮大附近有一個洞 – Borodin 2015-06-12 08:04:58

4

在使用eval編譯新的替代方法可能是最簡單的,你可以創建一個取代爲更加模塊化:

use warnings; 
use strict; 

sub subst { 
    my ($search, $replace, $mod) = @_; 

    if (my $eval = $mod =~ s/e//g) { 
     $replace = qq{'$replace'}; 
     $replace = "eval($replace)" for 1 .. $eval; 
    } else { 
     $replace = qq{"$replace"}; 
    } 
    sub {s/(?$mod)$search/$replace/ee} 
} 

my $sub = subst '(abc)', 'uc $1', 'ise'; 

local $_ = "my Abc string"; 

$sub->(); 

print "$_\n"; # prints "my ABC string" 

這只是輕輕測試,它留作練習爲讀者執行其他標誌,如g

+0

+1聰明,只要採取安全防範措施... – dawg 2010-07-13 19:16:12

+0

這似乎是一個好方法。我會看看。謝謝。 – bem33 2010-07-14 02:04:40

+0

爲什麼每個替代都有一個'ee'修飾符? – runrig 2010-07-14 15:57:00

2

當然s/$search/$replace/按照您的預期工作。這是動態修飾符,不直截了當。

對於常規匹配modifierspimsx,您可以使用Perl的Extended Patterns作爲模式的一部分即時修改修飾符標誌。這些格式爲(?pimsx-imsx)可打開/關閉這些修改器。

對於s//eee表單,您可以使用(?{ perl code})記錄在同一個perlre部分。對於所有evaleee表單,請考慮結果代碼的安全性!

沒有任何形式可以修改我知道的全局匹配,所以全局匹配和第一次匹配需要單獨的語句。

2

下面是Kinopiko的答案和評估的組合。

eval在此用於以受控和可維護的方式生成查找表,並且使用查找表來保存所有不太樂於查看的if ... elsif .. elsif。

(非常輕度測試)

my @stuff = (
{ 
    search => "this", 
    replace => "that", 
    modifier => "g", 
}, 
{ 
    search => "ono", 
    replace => "wendy", 
    modifier => "i", 
} 
); 
$_ = "this ono boo this\n"; 

my @modifiers = qw{m s i x g e}; 

my $s_lookup = {}; 

foreach my $modifier (@modifiers) { 
    $s_lookup->{$modifier} = eval " sub { s/\$_[0]/\$_[1]/$modifier } "; 
} 

for my $h (@stuff) { 
    $s_lookup->{$h->{modifier}}->($h->{search},$h->{replace}); 
} 

print; 

爲了這需要充分有用:可能改性劑

  1. 組合
  2. 查找表
  3. 排序功能,以便 'MSI' 組合與「錯'組合將會走向同一個關鍵。
+0

或者只是將修飾符驗證檢查添加到其他評估答案,例如現在的答案。 – runrig 2010-07-14 15:43:49