Массив объектов поиска для сопоставления возможных нескольких значений с использованием различных операторов сравнения

У меня есть функция для поиска в массиве объектов совпадающего значения с помощью оператора eq, например:

sub find {
    my ( $self, %params ) = @_;
    my @entries = @{ $self->{_entries} };

    if ( $params{filename} ) {
        @entries = grep { $_->filename eq $params{filename} } @entries;
    }
    if ( $params{date} ) {
        @entries = grep { $_->date eq $params{date} } @entries;
    }
    if ( $params{title} ) {
        @entries = grep { $_->title eq $params{title} } @entries;
    }
    ....

Я также хотел иметь возможность передавать переменную qr в кавычках для использования в сравнении, но единственный способ, которым я могу придумать разделение сравнений, — это использовать блок if/else, например:

if (lc ref($params{whatever}) eq 'regexp') {
    #use =~
} else {
    #use eq
}

Есть ли более короткий способ сделать это? По не зависящим от меня причинам я использую Perl 5.8.8, поэтому не могу использовать оператор интеллектуального сопоставления.

ТИА


person Sparkles    schedule 14.05.2010    source источник


Ответы (2)


Это Perl, поэтому, конечно, есть модуль CPAN: Match::Smart. Он работает очень похоже на оператор интеллектуального сопоставления Perl 5.10, только вы вводите smart_match($a, $b), а не $a ~~ $b.

Вы можете сравнить с документацией perlsyn для версии 5.10. smartmatching as Match::Smart обрабатывает еще несколько ситуаций.

В остальном не вижу ничего плохого в:

sub smart_match {
    my ($target, $param) = @_;
    if (ref $param eq 'Regexp') {
        return ($target =~ qr/$param/);
    }
    else {
        return ($target eq $param);
    }
}

@entries = grep { smart_match($_->date, $params{date}) } @entries;
person rjh    schedule 14.05.2010
comment
+1 за то, что познакомил меня с новым модулем, который мне, возможно, придется установить скрытно на $work. - person Ether; 14.05.2010
comment
И теперь я знаю о Match::Smart. Хо-хо-хо. - person darch; 14.05.2010

Я не знаю точно, что вы хотите, чтобы ваш конечный результат был, но вы можете сделать:

for my $field (qw(filename date title)) {
  my $p = $param($field};
  @entries = (ref($p) eq 'regexp')
    ? grep { $_->$field =~ /$p/ } @entries
    : grep { $_->$field eq $p }   @entries;
}

В качестве альтернативы вы можете превратить даже ваши сравнения «eq» в регулярные выражения, например:

my $entry = "string to be equal to";
my $re = qr/^\Q$entry\E/;

и это упрощает логику цикла for.

person runrig    schedule 14.05.2010