2010-10-23 57 views
1

我有一個Perl模塊,將文本與數百個正則表達式進行匹配;目前我只是oring他們:什麼是應用許多Perl正則表達式測試的最佳方式?

if (
    /?:re1/ or 
    ... 
    /re200$/ 
) { return "blah"; } 

是否有更好/更快/更少資源密集型的方式來做到這一點?也許存在一個有用的模塊,或者我應該將它們存儲在散列中等。

+1

可能的重複[我如何有效地匹配Perl中的許多不同的正則表達式模式?](http://stackoverflow.com/questions/1478083/how-can-i-efficiently-match-many-different-regex-patterns -in-perl) – daxim 2010-10-23 14:43:01

回答

10

看看Regexp::Assemble

這是從該描述:

正則表達式::組裝花費的正則表達式的任意數量,並將它們組裝成一個單一的正則表達式(RE或)相匹配的所有各單獨RE匹配。

因此,不需要大量的表達式循環,只需要針對一個表達式測試目標字符串。當你有幾千種模式需要處理時,這很有趣。認真努力製作出儘可能小的圖案。

也可以跟蹤原始模式,以便確定組成模式的源模式中哪一個是導致匹配發生的模式。

我用它來做一些項目,它非常棒。

+1

我使用Regexp :: Assemble從澳大利亞地址列表中提取城鎮名稱。根據官方數據來源,這些數據大約有10,000個,而我必須提取城鎮的代碼速度令人難以置信。 – singingfish 2010-10-23 07:53:41

+0

它產生的正則表達式可以令人興奮。 – 2010-10-23 09:48:44

+0

+1:你打敗了我。我正在使用Regexp :: Assemble在拍攝時匹配1700左右的術語,它的工作原理*很棒*。 – 2010-10-23 10:27:14

1

您可以將您的正則表達式保存在單獨的文件中,每行一個。它不會運行得更快,但代碼會更清晰。

讀他們喜歡的東西

my @patterns; 
while (<>) { 
    push @patterns, qr/$_/; 
} 

爲了提高性能,我唯一的建議是使用一個真正的解析器。 ANTLR的perl目標似乎已不存在,但我沒有遇到過使用通過perl的Inline::Java在Java中生成的解析器的麻煩。

編輯:沒有想到另一件小事:從最常見匹配到最不常見匹配的順序排列正則表達式。可以給你一個小的不變因素改進。

1

如果您的regexps沒有改變,那麼您應該使用/ o後綴,這將需要它們只被編譯一次。這將極大地提高速度。

此外,可以通過「最常見的拒絕優先」或「最少通配的優先」來排序它們,以便稍後使用更多的CPU密集型應用程序的執行次數最少。

從文件中讀取它們當然是可以的,但爲了提高速度,正確的方法是先讀取它們,然後在文本字符串中構造一個子例程,然後評估文本字符串以返回一個匿名子例程呼叫。這爲您提供了硬編碼regexps列表的速度優勢,並具有可變列表的正則表達式的靈活性。

+0

qr //更方便,子代在5.5.3之前。 – 2010-10-23 09:55:54

7

從的perlfaq6答案How do I efficiently match many regular expressions at once?


如何有效地在一次匹配許多正則表達式?

(貢獻的布賴恩·d FOY)

如果你有Perl 5.10或更高版本,這幾乎是微不足道的。你對正則表達式對象的數組只是智能匹配:

my @patterns = (qr/Fr.d/, qr/B.rn.y/, qr/W.lm./); 

if($string ~~ @patterns) { 
    ... 
    }; 

當它找到一個匹配,所以它並沒有去嘗試每一個表情的智能匹配停止。

早於Perl 5.10,你有一些工作要做。你想避免每次你想匹配它時編譯一個正則表達式。在這個例子中,perl的必須重新編譯的正則表達式foreach循環的每次迭代,因爲它沒有辦法知道$格局將是:

my @patterns = qw(foo bar baz); 

LINE: while(<DATA>) { 
    foreach $pattern (@patterns) { 
     if(/\b$pattern\b/i) { 
      print; 
      next LINE; 
      } 
     } 
    } 

的QR //運營商在Perl 5.005露面。它編譯一個正則表達式,但不適用它。當你使用預編譯版本的正則表達式時,perl的工作量會減少。在這個例子中,我插入一張地圖將每個模式轉換爲預編譯的形式。其餘的腳本是相同的,但速度更快:

my @patterns = map { qr/\b$_\b/i } qw(foo bar baz); 

LINE: while(<>) { 
    foreach $pattern (@patterns) { 
     if(/$pattern/) 
      { 
      print; 
      next LINE; 
      } 
     } 
    } 

在某些情況下,您可能可以將多個模式製作爲單個正則表達式。謹防需要回溯的情況。

my $regex = join '|', qw(foo bar baz); 

LINE: while(<>) { 
    print if /\b(?:$regex)\b/i; 
    } 

有關正則表達式效率的更多詳細信息,請參閱掌握Jeffrey Freidl的正則表達式。他解釋了正則表達式引擎是如何工作的以及爲什麼某些模式效率低得驚人。一旦你瞭解perl如何應用正則表達式,你可以調整它們以適應個別情況。

+0

因爲在perl文檔___中沒有看到這個__,所以我應該把它拿走。順便說一句,你列入「貢獻」的嚴重性並不會丟失在我身上。感謝您的幫助! – mikewaters 2010-10-23 16:07:33

相關問題