最简单的方法来匹配字符串数组在Perl中搜索?

最简单的方法来匹配字符串数组在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 
+6

Perl并不是真正的魔法。这只是Arthur C. Clarke先进技术的一个例子,与魔法无法区分:) 然后,我认为这个整体格式的东西是我个人认为的巫术:( – DVK 2010-06-11 02:30:25

+0

最近怎么样?如果你需要做一些事情在元素列表中,你必须以某种方式循环它们,你可能不会明确地使用'for'或'while',但是在一天结束时,即使是最深奥的解决方案也会使用某种类型的循环。 – 2010-06-11 18:13:59

+0

@kemp - 最近有没有其他的反循环问题,我错过了? – DVK 2010-06-12 13:32:59

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. 
+0

感谢这个详细和翔实的答案:D这个信息写得很好,很有用。 – 2010-06-11 21:11:04

+0

我还有一个与此相关的问题。我想用一个2维数组值来实现这个功能来搜索,但我不确定如何使用除了选项3之外的任何值。3对此的建议? (我编辑了这个问题,以反映新的数组) – 2010-06-13 01:59:41

+0

@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

+0

OP特别指出“或者我注定要使用循环?” - 这对我来说听起来像他知道他可以在一个循环中做到这一点,并正在寻找一个非循环的答案。我可能会错读他 – DVK 2010-06-11 02:03:32

+0

谢谢你指出,完全错过了它。 – 2010-06-11 02:09:02

+0

嘿......当然地图可以被认为是变相循环:) – DVK 2010-06-11 02:16:31

这里是建立具有嵌入代码正则表达式来递增索引溶液作为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个术语的库,它与之匹配,并且表现非常好。