如何在 Perl 数组中搜索匹配的字符串?

Posted

技术标签:

【中文标题】如何在 Perl 数组中搜索匹配的字符串?【英文标题】:How do I search a Perl array for a matching string? 【发布时间】:2011-02-24 22:03:08 【问题描述】:

在 Perl 中通过字符串数组搜索匹配字符串的最聪明的方法是什么?

一个警告,我希望搜索不区分大小写

所以"aAa" 将在("aaa","bbb")

【问题讨论】:

你会在列表中搜索多少次? 实际上只会搜索一次。运行时复杂性并不是我真正担心的 无关紧要,或者有任何关联,但是如果您将数组保存在一组散列键中(所有值都为“whatever”),您可以找出它是否存在或尽管不区分大小写确实会带来问题,但速度并没有快多少……哦,是的,而且 ~~ smartmatch 可能很慢……否则,请坚持使用 Ether 有据可查的答案,证明最简单的答案并不总是最好的答案,即使不是从你的角度来看,也是正确的答案。 【参考方案1】:

对于布尔匹配结果或出现次数,您可以使用:

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'

不需要使用模块。 当然,它不像上面的一些代码那样“可扩展”和通用。 我将其用于交互式用户答案,以匹配一组预定义的不区分大小写的答案。

【讨论】:

【参考方案2】:

这取决于您希望搜索做什么:

如果要查找所有匹配项,请使用内置的grep:

my @matches = grep  /pattern/  @list_of_strings;

如果您想找到第一个匹配项,请在List::Util 中使用first

use List::Util 'first';  
my $match = first  /pattern/  @list_of_strings;

如果要查找所有匹配项的计数,请在List::MoreUtils 中使用true

use List::MoreUtils 'true';
my $count = true  /pattern/  @list_of_strings;

如果您想知道第一个匹配的索引,请在List::MoreUtils 中使用first_index

use List::MoreUtils 'first_index'; 
my $index = first_index  /pattern/  @list_of_strings;

如果您只想知道是否有匹配项,但您不关心它是哪个元素或它的值,请在List::Util 中使用any

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

所有这些示例的核心都是类似的事情,但它们的实现已经过高度优化,速度很快,并且比你自己用grep、map 或 @ 编写的任何纯 perl 实现都要快987654328@.


请注意,执行循环的算法与执行单个匹配是一个单独的问题。要不区分大小写地匹配字符串,您可以简单地在模式中使用i 标志:/pattern/i。如果您以前没有阅读过perldoc perlre,那么您绝对应该阅读。

【讨论】:

您假设“匹配”表示正则表达式匹配,但给出的示例只是(不区分大小写)相等。 true 有点矫枉过正。比my $count = grep /pattern/ @list_of_strings;快吗? @Zaid 甚至是perldoc perlrequick,然后是perldoc perlreut Zaid 和 Telemachus:perlretquick 和 perlretut 都在 perlre 描述的第一段中特别提到。这是最好的开始,因为它为读者提供了如何沿着学习路径进行的路线图。 (除非您处于腕管综合症的终端,或者只是讨厌多点击一次鼠标)。【参考方案3】:
#!/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;

【讨论】:

【参考方案4】:

Perl 字符串匹配也可用于简单的是/否。

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

if ("@foo" =~ /\bhello\b/)
    print "found";

else
    print "not found";

【讨论】:

这在某些情况下会导致误报,例如my @foo = ( "hello world hello bar" ); 对误报的良好观察。意识到这一点,我发现这对于单字测试来说既好又简单。如有必要,总是可以使用连接添加分隔符 - 例如使用 \x01 将适用于大多数文本字符串。【参考方案5】:

Perl 5.10+ 包含“智能匹配”运算符~~,如果某个元素包含在数组或散列中,则返回 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!"

【讨论】:

请注意智能匹配功能是实验性的 (source) 2020 年还是实验性的吗?关于是否使用等,似乎众说纷纭:curiousprogrammer.wordpress.com/2010/06/15/… Strawberry Perl 5.30 仍然发出“Smartmatch 是实验性的”...【参考方案6】:

如果您要对数组进行多次 搜索,AND 匹配总是被定义为字符串等价,那么您可以规范化您的数据并使用哈希。 p>

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 或可以通过规范化满足的其他要求(如不区分大小写)时才有效。

【讨论】:

【参考方案7】:

我猜

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

会成功的。

【讨论】:

也许:@bar = grep(/^aaa$/i, @foo);因为你写的会搜索所有以 /aaa/i 开头的字符串,所以它也会找到 /aaaa/ 和 /aaaa+/。 我认为使用grep lc $_ eq 'aaa', @foo 会更有效,从而避免了正则表达式处理的需要。 全部正确,并且根据用例非常有效。但我想 OP 给出的例子对他的问题只是稍微有代表性。

以上是关于如何在 Perl 数组中搜索匹配的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

在perl中搜索两个匹配项

在 Perl 中,如何调用字符串中名称的方法?

如何在 Perl 中仅匹配 Unicode 字符串中的完全组合字符?

如何将正则表达式捕获存储在 Perl 的数组中?

如何根据 sql 中的匹配数针对关键字数组和排序结果搜索字符串?

如何在 Perl 中的匹配大括号之间提取字符串?