2009-06-23 84 views
5

我正在使用C#來連續搜索大字符串中的多個字符串「關鍵字」,這是大於4kb。這段代碼不斷循環,睡眠不會在保持合理的速度的同時減少足夠的CPU使用。緩衝是關鍵字匹配方法。C#:高效地搜索大字符串發生其他字符串

我發現了一些可能性,它們都具有相似的效率。

1)http://tomasp.net/articles/ahocorasick.aspx - 我沒有足夠的關鍵字使其成爲最有效的算法。

2)正則表達式。使用實例級別,編譯正則表達式。 - 提供比我需要的更多功能,效率不夠。

3)String.IndexOf。 - 我需要做一個「智能」版本,因爲它提供了足夠的效率。循環訪問每個關鍵字並調用IndexOf不會削減它。

有誰知道任何算法或方法,我可以用來實現我的目標?

+0

拾遺從下面的評論,字符串的轉換的迴避信息,並保持在東西[字節數組](http://stackoverflow.com/a/283648/512671)可能是最快的;併爲字節數組實現一個定製的Boyer-Moore更快 – zanlok 2013-03-22 18:51:02

回答

3

你是否一直在尋找相同的關鍵字? 嘗試Boyer-Moore。它需要對關鍵字進行一些預處理,但之後會獲得速度。

3

我還沒有嘗試過,但你看過Rabin-Karp?顯然它有一個糟糕的最壞情況複雜性,但通常相當不錯。

你的關鍵詞是什麼樣的?特別是,它們是否總是由空格(或類似的東西)分隔?如果是這樣,你可以基本上查看字符串,一旦尋找「單詞」,然後創建一個單詞到該單詞索引列表的映射,或者可能只對您感興趣的關鍵字這樣做。

如果您可以提供有關確切情況的更多詳細信息(例如關鍵字,分隔符以及您需要的搜索結果),這將有所幫助。

+0

我一直在試圖利用Rabin-Karp。問題是,所有的實現都使用一個靜態模式長度來加速他們的算法。我無法做到這一點,當我在沒有恆定模式長度的情況下實現它時,計算時間呈指數增長。 – 2009-06-25 15:51:48

+0

哦: 我正在搜索的文本長度12286.我的模式始終是更短長度 - 從10到約50個字符的任意位置,只是轉換爲十六進制字符串的話。 (前。BitConverter.ToString(ENCODING.GetBytes(「無後坐力」))) 所有我需要的是知道我的任何圖案出現在文本中。 – 2009-06-25 15:56:18

+0

並且在這些單詞之前和之後總是有空格嗎?如果是這樣,你可以迭代文本中的單詞,並使用正常的HashSet 來檢測每個單詞是否是關鍵字? – 2009-06-25 16:14:11

2

我開發了一個高效利用的IndexOf的這個問題:

A better way to replace many strings - obfuscation in C#

它使用的關鍵字的列表,並在字符串中的下一個位置。這樣,您只需爲每個關鍵字調用一次IndexOf,然後再爲每次找到的匹配調用一次。當您替換大字符串中的關鍵字時,它非常有效,因爲您可以從開始到結束處理字符串,而不是爲每個關鍵字處理整個字符串。我不知道你爲什麼要尋找字符串中的關鍵字,以及你如何處理字符串,但也許這對你的情況可能有用。

2

其實我之前必須解決這個問題,它有點兒有趣。我有20k的html頁面,每個頁面都有一個標題,並且希望所有其他頁面上出現的標題鏈接到具有該標題的頁面。聽起來和你想要完成的事情非常相似。

該方法:

  1. 進程的文件的通過將其變成其中單詞被確定爲連續的字母數字序列與幾個特殊字符{字,空白}的鏈接列表的文本,而空白就是導致下一個單詞的一切。
  2. 對於我想鏈接到的頁面的每個「標題」,重複步驟1中的過程。
  3. 然後將第1步中鏈接列表中節點的每個單詞添加到二進制排序列表中。
  4. 現在,你只需要第2步走,從每一個標題鏈接列表中的第一個字,並尋求到從第3步二進制排序列表您可能會發現幾命中,甚至軟命中當一個字是複數,所以你可能你需要測試二進制列表中的幾個起始節點。
  5. 將文檔處理爲步驟1中描述的表單後,通過插入新節點和/或修改空白值實際上非常容易修改。一旦完成,您只需遍歷整個列表並將其全部轉儲到流中。

這聽起來比現在要複雜得多,花了大約兩天的時間纔得到它的效果。

但是你解決它,有樂趣:)

0

我只是張貼這一個類似的線程,但它可能是更多的與此有關。

我做了類似的搜索,基本上找的約45K字節的文本內的長約10-50個字節的關鍵字。我搜索了超過900萬個關鍵字的1900個關鍵字,因此儘可能快地獲得這些關鍵字也是一個類似的優先事項。

因此,我發現使用.NET 4的最快方法是並行Regex IsMatch。

這裏獲得總場比賽的一個例子 -

needles.AsParallel ().Sum (l => Regex.IsMatch (haystack , Regex.Escape (l)) ? 1 : 0); 

這適用於我的情況(上圖),它比序的indexOf並行比較快55%,在我的測試至少在排序數據大小我的正在使用。我也想象只有在使用多核機器時纔會提高速度。

如果有人可以找到更快的方法會感興趣嗎?