How do I search a Perl array for a matching string?
What is the smartest way of searching through an array of strings for a matching string in Perl?
One caveat, I would like the search 开发者_开发问答to be case-insensitive
so "aAa"
would be in ("aaa","bbb")
It depends on what you want the search to do:
if you want to find all matches, use the built-in grep:
my @matches = grep { /pattern/ } @list_of_strings;
if you want to find the first match, use
first
in List::Util:use List::Util 'first'; my $match = first { /pattern/ } @list_of_strings;
if you want to find the count of all matches, use
true
in List::MoreUtils:use List::MoreUtils 'true'; my $count = true { /pattern/ } @list_of_strings;
if you want to know the index of the first match, use
first_index
in List::MoreUtils:use List::MoreUtils 'first_index'; my $index = first_index { /pattern/ } @list_of_strings;
if you want to simply know if there was a match, but you don't care which element it was or its value, use
any
in List::Util:use List::Util 1.33 'any'; my $match_found = any { /pattern/ } @list_of_strings;
All these examples do similar things at their core, but their implementations have been heavily optimized to be fast, and will be faster than any pure-perl implementation that you might write yourself with grep, map or a for loop.
Note that the algorithm for doing the looping is a separate issue than performing the individual matches. To match a string case-insensitively, you can simply use the i
flag in the pattern: /pattern/i
. You should definitely read through perldoc perlre if you have not previously done so.
I guess
@foo = ("aAa", "bbb");
@bar = grep(/^aaa/i, @foo);
print join ",",@bar;
would do the trick.
Perl 5.10+ contains the 'smart-match' operator ~~
, which returns true if a certain element is contained in an array or hash, and false if it doesn't (see perlfaq4):
The nice thing is that it also supports regexes, meaning that your case-insensitive requirement can easily be taken care of:
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!"
If you will be doing many searches of the array, AND matching always is defined as string equivalence, then you can normalize your data and use a hash.
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";
Let me emphasize that doing a hash lookup is good if you are planning on doing many lookups on the array. Also, it will only work if matching means that $foo eq $bar
, or other requirements that can be met through normalization (like case insensitivity).
#!/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 can also be used for a simple yes/no.
my @foo=("hello", "world", "foo", "bar");
if ("@foo" =~ /\bhello\b/){
print "found";
}
else{
print "not found";
}
For just a boolean match result or for a count of occurrences, you could use:
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"
};
}
Output:
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'
Does not require to use a module.
Of course it's less "expandable" and versatile as some code above.
I use this for interactive user answers to match against a predefined set of case unsensitive answers.
精彩评论