2014-02-15 2 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 первого предположения было удаление дополнительных регулярных выражений косых черт, в случае, . делает 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; просто строка, содержащая шаблон. Этот шаблон необходимо скомпилировать как Regex. – DavidO

+0

... потому что хеш-ключи не могут быть ссылками (включая ссылки на объекты), они могут быть только неизменяемыми строками. – DavidO

+0

Вероятно, вы должны настроить семантику вызова как нечто подобное: 'call_on_match ([[$ re_obj1 => \ & func1], [$ re_obj2 => \ & func2]]);' – DavidO

ответ

1

Я предлагаю вам использовать идентификаторы в качестве ключей в обоих хэшей, как этот

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' определяется в основной программе? Я не могу представить ситуацию, когда вы знаете регулярное выражение, но не соответствующий ему ключ в хеше. Как вы будете называть 'call_on_match', если вы не используете ключи в'% regexps'? – Borodin

+0

Я буду использовать некоторое регулярное выражение не из '% regexps', очевидно. Фактически массив регулярных выражений может быть предоставлен каким-либо другим модулем или таковым и не находится в файле, где 'call_on_match' делает. –

Смежные вопросы