2010-12-14 27 views
3

我正在尋找同時匹配兩個值的最佳方法。如何在字符串中獨立於它們的相應位置來匹配兩個值

我想獲得一個真正的價值,如果這兩個值是一個字符串,但我不知道以何種順序它們出現的字符串(例如,在案件abcdefbedfa我想匹配ab

是否有更好的解決方案(尤其是如果以後我需要更復雜的值,以匹配)比:

$string =~ m/(a.*b)|(b.*a)/i 

回答

11
$string =~ /a/i && $string =~ /b/i; 
+0

我有這個版本,但認爲它不是優雅的。 – Pit 2010-12-14 15:45:42

+3

@Pit,當優雅與清晰不一致時,選擇清晰。交替的方法和先行的方法可能看起來更優雅,但如果我試圖維護你的代碼,即使我能夠立即理解這些機制,也需要幾秒鐘的時間才能明白代碼的意圖。這兩種表達方式在所做的事情上更爲直接,找到兩種模式都獨立於另一種模式。 – 2010-12-14 18:50:58

+0

你有一個點there.I然而也試圖優化我的代碼在速度和資源使用方面,並認爲一個稍微複雜的正則表達式可能比兩個簡單的正則表達式結合邏輯和。這種情況可能並非如此簡單,但如果我錯了,請糾正我的錯誤。 – Pit 2010-12-14 21:25:51

5

您可以使用正向前查找爲:

$string =~ /^(?=.*a)(?=.*b).*$/i 

一般來說,如果你想查詢的foo存在和bar在字符串中的任何地方,你可以這樣做:

$string =~ /^(?=.*foo)(?=.*bar).*$/i 

如果你想在foobar作爲單獨的單詞,而不是任何其他單詞的子如果你想添加的支票的baz存在你可以做

$string =~ /^(?=.*\bfoo\b)(?=.*\bbar\b).*$/i 

後來:

,您可以添加單詞邊界,
$string =~ /^(?=.*\bfoo\b)(?=.*\bbar\b)(?=.*\bbaz\b).*$/i 
+0

我仍然無法理解預測,但您的解決方案有效。 Thx – Pit 2010-12-14 15:46:41

+1

@Pit:我會推薦你​​這個鏈接:http://www.regular-expressions.info/lookaround.html,它對lookahead有很好的解釋。 – codaddict 2010-12-14 15:51:53

1

爲什麼不只是這樣?

$string =~ /a/i && $string =~ /b/i 

它更清晰。

3

從我的評論擴展這裏是幾個解決方案的比較。

#!/usr/bin/perl 

use strict; 
use warnings; 
use Benchmark qw(cmpthese); 

my $two_regexp = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ /this/i && $string =~ /that/i) { 
      1; 
     } 
    } 
}; 

my $alternation = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ m/(this.*that)|(that.*this)/i) { 
      1; 
     } 
    } 
}; 

my $alternation_no_capture = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ m/(?:this.*that)|(?:that.*this)/i) { 
      1; 
     } 
    } 
}; 

my $anchored_lookahead = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ /^(?=.*this)(?=.*that).*$/i) { 
      1; 
     } 
    } 
}; 

my $start_anchored_lookahead = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ /^(?=.*this)(?=.*that)/i) { 
      1; 
     } 
    } 
}; 

my $free_lookahead = q{ 
    for my $string ('This and that', 'Not that, this!', 'do not match this') { 
     if ($string =~ /(?=.*this)(?=.*that)/i) { 
      1; 
     } 
    } 
}; 

cmpthese(-1, { 
    two_regexp    => $two_regexp, 
    alternation    => $alternation, 
    alternation_no_capture => $alternation_no_capture, 
    anchored_lookahead  => $anchored_lookahead, 
    start_anchored_lookahead => $start_anchored_lookahead, 
    free_lookahead   => $free_lookahead, 
}); 

你應該用你的實際模式和一組真實數據來運行它,它可以從根本上改變結果。最近版本的Perl改變了regexp的性能,所以我的結果可能不會接近你的結果。在一個Perl 5.8.8盒子上,我得到了這些結果。

       Rate free_lookahead alternation alternation_no_capture anchored_lookahead start_anchored_lookahead two_regexp 
free_lookahead   170836/s    --  -55%     -61%    -61%      -67%  -73% 
alternation    378300/s   121%   --     -13%    -13%      -27%  -40% 
alternation_no_capture 432784/s   153%   14%      --    -1%      -17%  -31% 
anchored_lookahead  436906/s   156%   15%      1%     --      -16%  -30% 
start_anchored_lookahead 518950/s   204%   37%     20%    19%      --  -17% 
two_regexp    628278/s   268%   66%     45%    44%      21%   -- 

所以至少我的美學意義和使用兩場比賽的Perl版本都會贏得雙方。

相關問題