Как мне найти в массиве Perl подходящую строку? - PullRequest
36 голосов
/ 28 мая 2010

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

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

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

Ответы [ 7 ]

141 голосов
/ 28 мая 2010

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

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

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

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

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

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

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

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


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

29 голосов
/ 28 мая 2010

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!"
27 голосов
/ 28 мая 2010

Я думаю

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

сделает свое дело.

6 голосов
/ 28 мая 2010

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

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 или другие требования, которые могут быть выполнены посредством нормализации (например, нечувствительность к регистру).

5 голосов
/ 28 мая 2010
#!/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;
2 голосов
/ 02 августа 2014

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

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

if ("@foo" =~ /\bhello\b/){
    print "found";
}
else{
    print "not found";
}
1 голос
/ 28 февраля 2016

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

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'

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

...