2013-02-11 70 views
6

我正在寫一個運行字符串就很多了一些正則表達式(〜10)(〜25元)C#應用程序。我曾嘗試谷歌這一點,但任何搜索與「減慢」的正則表達式都充滿了關於如何反向引用等減緩正則表達式的教程。我認爲這不是我的問題,因爲我的正則表達式開始快速並且減速。正則表達式性能下降

對於第一個一百萬左右的字符串需要60ms的每1000串左右運行正則表達式。到最後,它的速度會減慢到大約需要600毫秒。有誰知道爲什麼?

很糟糕,但我用的RegEx而非緩存版本的實例和編譯表情,我可以改進它。

我的一些正則表達式的需要因人而異例如這取決於用戶的名稱可能是 mike said (\w*)john said (\w*)

我的理解是,這是不可能的編譯那些正則表達式,並傳遞參數(例如saidRegex.Match(inputString, userName))。

有沒有人有任何建議?

[編輯,以準確反映速度 - 是每1000個字符串,而不是每串]

+6

你能發表一些代碼嗎? – 2013-02-11 17:18:45

+0

如果您採取了通常的措施來提高績效,那麼就很難提供更多建議。如果沒問題,你能顯示你的正則表達式嗎? – nhahtdh 2013-02-11 17:19:57

+17

正則表達式引擎本身不太可能放緩。更有可能的是,您的應用程序正在保存結果,因此內存在不斷增加,這會導致整體性能下降。監視你的進程內存大小。同時檢查內存泄漏。 – Barmar 2013-02-11 17:24:52

回答

2

這可能不是直接回答你關於正則表達式的性能下降的問題 - 這是有點迷人。然而 - 閱讀完所有的評論和討論上面的後 - 我建議如下:

解析一次數據,匹配數據分割出去到數據庫表。它看起來像你想捕捉以下字段:

Player_Name | Monetary_Value 

如果你要創建一個包含每行這些值的數據庫表,然後搭上每個新行作爲正在創建它 - 解析它 - 並添加到數據表中 - 您可以輕鬆地對數據進行任何類型的分析/計算 - 無需一次又一次解析25M行(這是浪費)。

此外 - 第一次運行時,如果要將25M記錄分解爲100,000個記錄塊,然後運行該算法250次(100,000 x 250 = 25,000,000) - 您可以享受所描述的所有性能不要放慢速度,因爲你在完成這項工作。

換句話說 - 考慮以下幾點:

  1. 創建一個數據庫表如下:

    CREATE TABLE PlayerActions (
        RowID   INT PRIMARY KEY IDENTITY, 
        Player_Name VARCHAR(50) NOT NULL, 
        Monetary_Value MONEY  NOT NULL 
    ) 
    
  2. 創建傷了你的25米行分解爲100K塊的算法。使用LINQ/EF5作爲假設的例子。

    public void ParseFullDataSet(IEnumerable<String> dataSource) { 
        var rowCount = dataSource.Count(); 
        var setCount = Math.Floor(rowCount/100000) + 1; 
    
        if (rowCount % 100000 != 0) 
         setCount++; 
    
        for (int i = 0; i < setCount; i++) { 
         var set = dataSource.Skip(i * 100000).Take(100000); 
         ParseSet(set); 
        } 
    } 
    
    public void ParseSet(IEnumerable<String> dataSource) { 
        String playerName = String.Empty; 
        decimal monetaryValue = 0.0m; 
    
        // Assume here that the method reflects your RegEx generator. 
        String regex = RegexFactory.Generate(); 
    
        for (String data in dataSource) { 
         Match match = Regex.Match(data, regex); 
         if (match.Success) { 
          playerName = match.Groups[1].Value; 
    
          // Might want to add error handling here. 
          monetaryValue = Convert.ToDecimal(match.Groups[2].Value); 
    
          db.PlayerActions.Add(new PlayerAction() { 
           // ID = ..., // Set at DB layer using Auto_Increment 
           Player_Name = playerName, 
           Monetary_Value = monetaryValue 
          }); 
          db.SaveChanges(); 
    
          // If not using Entity Framework, use another method to insert 
          // a row to your database table. 
         } 
        } 
    } 
    
  3. 運行上面的一個時間讓所有裝載了您的預先存在的數據。

  4. 創建掛鉤某處,它允許您檢測增加了一個新行。每次創建一個新的行時間,請撥打:

    ParseSet(new List<String>() { newValue }); 
    

    ,或者一次創建的倍數,請致電:

    ParseSet(newValues); // Where newValues is an IEnumerable<String> 
    

現在你可以做你想要的任何計算分析或數據挖掘數據,而不必擔心超過25m行的性能。

+0

注意:上面的代碼是在沒有編譯的情況下編寫的 - 所以我不能保證它按原樣工作,但它應該引導您正確的方向,如果你選擇實施解決方案如上所述。 – 2013-02-21 23:26:59

+1

我有點晚了,但非常感謝! – mike1952 2016-04-07 16:04:35

0

正則表達式需要時間進行計算。但是,你可以使用一些技巧來使它緊湊。 您也可以在C#中使用字符串函數來避免正則表達式函數。

該代碼會很長,但可能會提高性能。 字符串有幾個功能來剪切和提取字符,並根據需要進行模式匹配。 like eg:IndeOfAny,LastIndexOf,Contains ....

string str= "mon"; 
string[] str2= new string[] {"mon","tue","wed"}; 

if(str2.IndexOfAny(str) >= 0) 
{ 
    //success code// 
}