2014-02-15 63 views
-1

我有一些正則表達式的組,並且想爲它們中的每一個匹配當前行,如果匹配成功,調用一些具有匹配組作爲參數的函數。Perl,一組預編譯的正則表達式的匹配

my %regexps = (
    "a" => qr/^(a)\s*(b)/o, 
    "b" => qr/^(c)\s*(d)/o, 
    "c" => qr/^(e)\s*(f)/o, 
); 

sub call_on_match { 
    my $actions = shift; 
    # ... some setup actions for $_ 
    while (my ($regexp, $func) = each(%$actions)) { 
     if (my @matches = /$regexp/){ 
      $func->(@matches); 
     } 
    } 
} 

call_on_match({ 
    $regexps{"a"} => \&some_funca, 
    $regexps{"b"} => \&some_funcb, 
    $regexps{"c"} => \&some_funcc, 
}) 

的問題是在my @matches = /$regexp/表達時,它執行約110K倍和花費約1秒總編譯(此行的典型分析器輸出:# spent 901ms making 107954 calls to main::CORE:regcomp, avg 8µs/call 首先猜測是,以除去額外的regexp斜線,在情況下,它。令Perl認爲它是新的正則表達式,必須編譯我用my @matches = ($_ =~ $regexp),但沒有成功 是否有另一種辦法,使perl的不重新編譯qr'ed正則表達式在這種情況下

UPD:?我換成用哈希陣列(如[$regexps{"a"}, \&some_funca]):

foreach my $group (@$actions){ 
    my ($regexp, $func) = @$group; 
    if (my @matches = ($_ =~ $regexp)){ 
      $func->(@matches); 
    } 
} 

現在它編譯更快,但編譯並沒有消失:# spent 51.7ms making 107954 calls to main::CORE:regcomp, avg 479ns/call

+0

通過傳遞一個RegExp對象作爲匿名散列的關鍵字,它會串行化,並且不再是Regexp對象;只是一個包含模式的字符串。該模式將需要編譯爲正則表達式。 – DavidO

+0

...因爲散列鍵不能被引用(包括對象的引用),它們只能是不可變的字符串。 – DavidO

+0

你可能應該設置調用語義是這樣的:''call_on_match([[$ re_obj1 => \&func1],[$ re_obj2 => \&func2]]);' – DavidO

回答

1

我建議你使用的ID作爲鍵在哈希值,這樣

use strict; 
use warnings; 

my %regexps = (
    a => qr/^(a)\s*(b)/, 
    b => qr/^(c)\s*(d)/, 
    c => qr/^(e)\s*(f)/, 
); 

sub call_on_match { 

    my ($actions) = @_; 

    # ... some setup actions for $_ 

    while (my ($regexp_id, $func) = each %$actions) { 
    if (my @matches = $_ =~ $regexps{$regexp_id}) { 
     $func->(@matches); 
    } 
    } 
} 

call_on_match(
    { 
    a => \&some_funca, 
    b => \&some_funcb, 
    c => \&some_funcc, 
    } 
); 
+0

這可以防止我在使用從模塊加載的call_on_match函數的其他腳本中使用其他一些正則表達式。不是我真正想要的東西。 –

+0

@SirAnthony:如果你解釋真正的問題,我相信我們可以幫助你找到更好的解決方案。你是說'call_on_match'由一個模塊提供,但'%regexps'是在主程序中定義的嗎?我無法想象這種情況,你會知道正則表達式,但不知道哈希中的對應鍵。如果你不知道'%regexps'中的密鑰是什麼,你將如何調用'call_on_match'? – Borodin

+0

顯然,我會使用一些正則表達式,而不是'%regexps'。事實上,一些正則表達式可能由另一個模塊或類似的東西提供,並不駐留在'call_on_match'所在的文件中。 –