2010-06-11 82 views
7

我想要做的是檢查一個字符串數組與我的搜索字符串,並獲取相應的密鑰,以便我可以將其存儲。有沒有用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

回答

11

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

1

一個簡單的方法就是使用一個哈希和正則表達式:

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

2

這裏是建立具有嵌入代碼正則表達式來遞增索引溶液作爲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})加入正則表達式字符串。

0

你也可以看看Regexp::Assemble,它將採集一個子正則表達式的集合,並從它們中構建一個超正則表達式,然後可以用它們一次測試所有這些正則表達式(並給出文本當然與正則表達式匹配)。我不確定這是否是最好的解決方案,如果您只查看三個要匹配的字符串/正則表達式,但是如果您有更大的目標集合 - 我最初使用它的項目有一個約1500個術語的庫,它與之匹配,並且表現非常好。

相關問題