如何在 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 中仅匹配 Unicode 字符串中的完全组合字符?