最简单的方法来匹配字符串数组在Perl中搜索?
我想要做的是检查一个字符串数组与我的搜索字符串,并获取相应的密钥,以便我可以将其存储。有没有用Perl这样做的神奇方式,或者我注定要使用循环?如果是这样,那么最有效的方法是什么?最简单的方法来匹配字符串数组在Perl中搜索?
我是比较新的Perl的(我只写了其他2个脚本),所以我不知道很多神奇的是,仅仅是Perl是魔术= d
Reference Array: (1 = 'Canon', 2 = 'HP', 3 = 'Sony')
Search String: Sony's Cyber-shot DSC-S600
End Result: 3
UPDATE:
基础上讨论在this question的结果,这取决于你的意图/什么构成“不使用循环”的标准,低于map
基础的解决方案(见“选项#1)可能是最简明的解决方案,只要你不consi一个循环(答案的简短版本是:就实现/性能而言,它是一个循环,从语言理论的角度来看,这不是一个循环)。
假设你不关心你是否获得“3”或“索尼”作为答案,你可以不用在一个简单的情况下一个循环,通过构建一个正则表达式用“或”从阵列逻辑(|
),如下所示:Sony
正则表达式将会(一旦变量$combined_search
由Perl的插值)TA:
my @strings = ("Canon", "HP", "Sony");
my $search_in = "Sony's Cyber-shot DSC-S600";
my $combined_search = join("|",@strings);
my @which_found = ($search_in =~ /($combined_search)/);
print "$which_found[0]\n";
从我的测试运行的结果关于表格/(Canon|HP|Sony)/
这就是你想要的。
这将无法正常工作,则如果任何字符串包含regex的特殊字符(如|
或)
) - 在这种情况下,你需要逃避他们
注意:我个人认为这个有点作弊,因为为了实现join()
,Perl本身必须在中介者的某个地方做一个循环。因此,这个答案可能无法满足您希望保持无循环的愿望,这取决于您是否想要避免出于性能考虑的循环,以及使代码更简洁还是更短。
P.S.要获得“3”而不是“索尼”,你将不得不使用循环 - 要么以一种明显的方式,通过在它下面的循环中进行1次匹配;或者使用一个库来避免你自己编写循环,但会在调用下面有一个循环。
我会提供3种替代解决方案。
#1选项: - 我的最爱。使用 “地图”,我个人仍然认为一个循环:
my @strings = ("Canon", "HP", "Sony");
my $search_in = "Sony's Cyber-shot DSC-S600";
my $combined_search = join("|",@strings);
my @which_found = ($search_in =~ /($combined_search)/);
print "$which_found[0]\n";
die "Not found" unless @which_found;
my $strings_index = 0;
my %strings_indexes = map {$_ => $strings_index++} @strings;
my $index = 1 + $strings_indexes{ $which_found[0] };
# Need to add 1 since arrays in Perl are zero-index-started and you want "3"
#2选项:使用的背后隐藏着一个很好的CPAN库方法的循环:
use List::MoreUtils qw(firstidx);
my @strings = ("Canon", "HP", "Sony");
my $search_in = "Sony's Cyber-shot DSC-S600";
my $combined_search = join("|",@strings);
my @which_found = ($search_in =~ /($combined_search)/);
die "Not Found!"; unless @which_found;
print "$which_found[0]\n";
my $index_of_found = 1 + firstidx { $_ eq $which_found[0] } @strings;
# Need to add 1 since arrays in Perl are zero-index-started and you want "3"
#3选项:这里有明显的循环方式:
my $found_index = -1;
my @strings = ("Canon", "HP", "Sony");
my $search_in = "Sony's Cyber-shot DSC-S600";
foreach my $index (0..$#strings) {
next if $search_in !~ /$strings[$index]/;
$found_index = $index;
last; # quit the loop early, which is why I didn't use "map" here
}
# Check $found_index against -1; and if you want "3" instead of "2" add 1.
感谢这个详细和翔实的答案:D这个信息写得很好,很有用。 – 2010-06-11 21:11:04
我还有一个与此相关的问题。我想用一个2维数组值来实现这个功能来搜索,但我不确定如何使用除了选项3之外的任何值。3对此的建议? (我编辑了这个问题,以反映新的数组) – 2010-06-13 01:59:41
@Ben - 你可能想创建它作为一个新的问题......(链接到这个问题),所以人们可以从可搜索性方面受益。 – DVK 2010-06-13 12:23:30
一个简单的方法就是使用一个哈希和正则表达式:
my $search = "your search string";
my %translation = (
'canon' => 1,
'hp' => 2,
'sony' => 3
);
for my $key (keys %translation) {
if ($search =~ /$key/i) {
return $translation{$key};
)
}
自然地,返回可以很容易地被打印。您也可以围绕在while循环整个事情:
while(my $search = <>) {
#your $search is declared = to <> and now gets its values from STDIN or strings piped to this script
}
也请看看Perl的正则表达式的功能在perlre 并看看Perl的数据结构在perlref
编辑
正如刚刚指出的那样,您试图摆脱使用循环。另一种方法是使用perl的map函数。看看here。
这里是建立具有嵌入代码正则表达式来递增索引溶液作为perl的移动通过正则表达式:
my @brands = qw(Canon HP Sony);
my $string = "Sony's Cyber-shot DSC-S600";
use re 'eval'; # needed to use the (?{ code }) construct
my $index = -1;
my $regex = join '|' => map "(?{ \$index++ })\Q$_" => @brands;
print "index: $index\n" if $string =~ $regex;
# prints 2 (since Perl's array indexing starts with 0)
被预置到每个品牌的字符串第一递增索引,然后尝试以匹配品牌(与quotemeta
(作为\Q
)转义,以允许在品牌名称中使用正则表达式特殊字符)。
当匹配失败时,正则表达式引擎移过|
,然后模式重复。
如果您有多个字符串匹配,请务必在每个字符串前重置$index
。或者你可以将(?{$index = -1})
加入正则表达式字符串。
你也可以看看Regexp::Assemble,它将采集一个子正则表达式的集合,并从它们中构建一个超正则表达式,然后可以用它们一次测试所有这些正则表达式(并给出文本当然与正则表达式匹配)。我不确定这是否是最好的解决方案,如果您只查看三个要匹配的字符串/正则表达式,但是如果您有更大的目标集合 - 我最初使用它的项目有一个约1500个术语的库,它与之匹配,并且表现非常好。
Perl并不是真正的魔法。这只是Arthur C. Clarke先进技术的一个例子,与魔法无法区分:) 然后,我认为这个整体格式的东西是我个人认为的巫术:( – DVK 2010-06-11 02:30:25
最近怎么样?如果你需要做一些事情在元素列表中,你必须以某种方式循环它们,你可能不会明确地使用'for'或'while',但是在一天结束时,即使是最深奥的解决方案也会使用某种类型的循环。 – 2010-06-11 18:13:59
@kemp - 最近有没有其他的反循环问题,我错过了? – DVK 2010-06-12 13:32:59