web-dev-qa-db-fra.com

Comment rechercher dans un tableau Perl une chaîne correspondante?

Quel est le moyen le plus intelligent de rechercher dans un tableau de chaînes une chaîne correspondante en Perl?

Une mise en garde, je voudrais que la recherche soit insensible à la casse

alors "aAa" serait dans ("aaa","bbb")

36
Mike

J'imagine

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

ferait l'affaire.

29
Peter Tillemans

Cela dépend de ce que vous voulez que la recherche fasse:

  • si vous voulez trouver toutes les correspondances , utilisez la fonction intégrée grep :

    my @matches = grep { /pattern/ } @list_of_strings;
    
  • si vous voulez trouver la première correspondance , utilisez first dans List :: Util :

    use List::Util 'first';  
    my $match = first { /pattern/ } @list_of_strings;
    
  • si vous voulez trouver le nombre de toutes les correspondances , utilisez true dans List :: MoreUtils :

    use List::MoreUtils 'true';
    my $count = true { /pattern/ } @list_of_strings;
    
  • si vous voulez connaître l'index de la première correspondance , utilisez first_index in List :: MoreUtils :

    use List::MoreUtils 'first_index'; 
    my $index = first_index { /pattern/ } @list_of_strings;
    
  • si vous voulez simplement savoir s'il y a une correspondance , mais vous ne vous souciez pas de savoir de quel élément il s'agit ni de sa valeur, utilisez any in List :: Util :

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

Tous ces exemples ont la même base, mais leurs implémentations ont été fortement optimisées pour être rapides et seront plus rapides que celles de pure-Perl avec lesquelles vous pourriez écrire vous-même grep , map ou a pour la boucle .


Notez que l’algorithme pour la mise en boucle est un problème distinct de celui qui consiste à effectuer les correspondances individuelles. Pour faire correspondre une chaîne sans tenir compte de la casse, vous pouvez simplement utiliser le drapeau i dans le motif: /pattern/i. Vous devez absolument lire perldoc perlre si vous ne l'avez pas déjà fait.

143
Ether

Perl 5.10+ contient l'opérateur 'smart-match' ~~, qui retourne true si un élément donné est contenu dans un tableau ou un hachage, et false si ce n’est pas le cas (voir perlfaq4 ):

Ce qui est bien, c’est qu’il prend également en charge les expressions rationnelles, ce qui signifie que vos besoins insensibles à la casse peuvent facilement être pris en charge:

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!"
29
Zaid

Si vous faites de nombreuses recherches dans le tableau, ET la correspondance est toujours défini comme une équivalence de chaîne, vous pouvez alors normaliser vos données et utiliser un hachage.

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";

Permettez-moi de souligner que faire une recherche de hachage est une bonne chose si vous envisagez de faire plusieurs recherches sur le tableau. En outre, cela ne fonctionnera que si l'appariement signifie que $foo eq $bar, ou d’autres exigences pouvant être satisfaites par la normalisation (comme l’insensibilité à la casse).

6
daotoad
#!/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;
5
Alex Reynolds

La correspondance de chaîne Perl peut également être utilisée pour un simple oui/non.

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

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

Pour un résultat de correspondance booléen ou un nombre d'occurrences, vous pouvez utiliser:

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"
    };
}

Sortie:

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'

Ne nécessite pas de tiliser un module.
Bien sûr, il est moins "extensible" et polyvalent que certains codes ci-dessus.
J'utilise ceci pour les réponses utilisateur interactives afin de les faire correspondre à un ensemble prédéfini de réponses non sensibles à la casse.

1
Gilles Maisonneuve