Как выполнить поиск в массиве Perl для соответствующей строки?

каков самый умный способ поиска через массив строк для соответствующей строки в Perl?

одно предостережение, я хотел бы, чтобы поиск был нечувствительным к регистру

так "aAa" будет ("aaa","bbb")

7 ответов


Я думаю

@foo = ("aAa", "bbb");
@bar = grep(/^aaa/i, @foo);
print join ",",@bar;

будет делать трюк.


это зависит от того, что вы хотите, чтобы поиск сделать:

  • если вы хотите найти все матчи используйте встроенный grep:

    my @matches = grep { /pattern/ } @list_of_strings;
    
  • если вы хотите найти первый матч используйте first на Список:: Util:

    use List::Util 'first';  
    my $match = first { /pattern/ } @list_of_strings;
    
  • если вы хотите найти количество всех матчей используйте true in Список::MoreUtils:

    use List::MoreUtils 'true';
    my $count = true { /pattern/ } @list_of_strings;
    
  • если вы хотите знать индекс первого матча используйте first_index на Список::MoreUtils:

    use List::MoreUtils 'first_index'; 
    my $index = first_index { /pattern/ } @list_of_strings;
    
  • если вы хотите просто знать если бы была спичка, но вам все равно, какой элемент это был или его значение, используйте any на Список:: Util:

    use List::Util 1.33 'any';
    my $match_found = any { /pattern/ } @list_of_strings;
    

все эти примеры похожи вещи в их ядре, но их реализации были сильно оптимизированы, чтобы быть быстрыми, и будут быстрее, чем любая реализация pure-perl, которую вы могли бы написать сами с grep, карта или цикл.


обратите внимание, что алгоритм выполнения цикла является отдельной проблемой, чем выполнение отдельных совпадений. Для сопоставления строк без учета регистра, вы можете просто использовать i флаг в шаблон: /pattern/i. Вы обязательно следует прочитать perldoc perlre если вы ранее этого не делали.


Perl 5.10 + содержит оператор "smart-match"~~, который возвращает true, если определенный элемент содержится в массиве или хэше, и false, если это не так (см. perlfaq4):

хорошая вещь в том, что она также поддерживает регулярные выражения, что означает, что ваше требование без учета регистра может быть легко позаботиться:

use strict;
use warnings;
use 5.010;

my @array  = qw/aaa bbb/;
my $wanted = 'aAa';

say "'$wanted' matches!" if /$wanted/i ~~ @array;   # Prints "'aAa' matches!"

Если вы будете делать много поиск в массиве, и соответствие всегда определяется как эквивалентность строк, затем вы можете нормализовать свои данные и использовать хэш.

my @strings = qw( aAa Bbb cCC DDD eee );

my %string_lut;

# Init via slice:
@string_lut{ map uc, @strings } = ();

# or use a for loop:
#    for my $string ( @strings ) {
#        $string_lut{ uc($string) } = undef;
#    }


#Look for a string:

my $search = 'AAa';

print "'$string' ", 
    ( exists $string_lut{ uc $string ? "IS" : "is NOT" ),
    " in the array\n";

позвольте мне подчеркнуть, что делаешь хэш-поиска хорошо, если вы планируете делать много поиска в массиве. Кроме того, он будет работать, только если сопоставление означает, что $foo eq $bar или другие требования, которые могут быть выполнены путем нормализации (например, нечувствительность к регистру).


#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

my @bar = qw(aaa bbb);
my @foo = grep {/aAa/i} @bar;

print Dumper \@foo;

Perl string match также может использоваться для простого Да / нет.

my @foo=("hello", "world", "foo", "bar");

if ("@foo" =~ /\bhello\b/){
    print "found";
}
else{
    print "not found";
}

только для логического результата матча или для количества вхождений вы можете использовать:

use 5.014; use strict; use warnings;
my @foo=('hello', 'world', 'foo', 'bar', 'hello world', 'HeLlo');
my $patterns=join(',',@foo);
for my $str (qw(quux world hello hEllO)) {
    my $count=map {m/^$str$/i} @foo;
    if ($count) {
        print "I found '$str' $count time(s) in '$patterns'\n";
    } else {
        print "I could not find '$str' in the pattern list\n"
    };
}

выход:

I could not find 'quux' in the pattern list
I found 'world' 1 time(s) in 'hello,world,foo,bar,hello world,HeLlo'
I found 'hello' 2 time(s) in 'hello,world,foo,bar,hello world,HeLlo'
I found 'hEllO' 2 time(s) in 'hello,world,foo,bar,hello world,HeLlo'

не требуется использовать модуль.
Конечно, это менее "расширяемый" и универсальный, как и некоторый код выше.
Я использую это для интерактивного пользователя ответы на матче против предопределенный набор случае unsensitive ответы.