2009-11-25 85 views
3

我想知道是否有任何關於何時使用正則表達式VS "string".contains("anotherString")和/或其他String API調用的一般準則?正則表達式與絕對迭代的最佳實踐

雖然上面給出的.contains()的決定是微不足道的(如果你可以在一次調用中做到這一點,爲什麼要打擾正則表達式),現實生活帶來了更復雜的選擇。例如,做兩個.contains()調用還是一個正則表達式更好?

我的經驗法則是總是使用正則表達式,除非這可以用一個API調用來替代。這可以防止代碼反對膨脹,但從代碼可讀性的角度來看可能不是很好,特別是如果正則表達式趨於變大。

另一個經常被忽視的觀點是性能。我如何知道這個正則表達式需要多少迭代(如「大O」)?它會比純粹的迭代更快嗎?不知何故,每個人都假設一旦正則表達式比5 if語句短,它肯定會更快。但是,情況總是如此嗎?如果正則表達式不能預先編譯,這尤其重要。

回答

-1

答案與往常一樣,取決於它。

在你的具體情況下,我猜想替代方法是做正則表達式「this | that」,然後做一個find。這個特定的結構真正刺探了正則表達式的弱點。在這種情況下,「OR」並不真正知道子模式試圖做什麼,因此無法輕鬆優化。它最終做相當於(僞代碼):

for(i = 0; i < stringLength; i++) { 
    if(stringAt pos i starts with "this") 
     found! 
    if(stringAt pos i starts with "that") 
     found! 
} 

幾乎沒有一個更慢的方法來做到這一點。在這種情況下,兩個包含()的調用會快得多。

另一方面,完整匹配:".*this.*|.*that.*"可能會優化得更好。

對於我來說,應該使用正則表達式,否則代碼做的很複雜或笨拙。所以如果你想在目標字符串中找到兩個或三個字符串中的一個,那麼就使用contains。但是,如果你想找到以'A'或'B'開始並以'g'結尾的單詞 - 'm'...那麼使用正則表達式。

然後你不會在這裏和那裏擔心幾個週期。

+3

你的答案根本沒有意義。正則表達式這個|在字符串中進行一次線性搜索,當遇到「th」時只有一點額外的邏輯,停止在這個或那個的第一個匹配處。使兩個包含()調用對字符串進行兩次線性搜索,如果不包含第一個單詞,則需要搜索完整字符串。這總會有更糟糕的表現。 。*。*。* *絕對不會優化得更好,因爲最初的。*匹配整個字符串直到結束,然後回溯以找到單詞。 – 2010-02-25 02:09:19

+0

最糟糕的情況是相同的,每個模式都會在每個相關的字符位置進行嘗試。對於少數直接比賽,我同意「this | that」具有更多最佳情況(例如,'that'發生在字符串中,但不是'this')。隨着模式列表的增長以及錯誤開始的可能性增加,它會發生變化。在這種情況下,我可能離開了基地。直接文字匹配可能總是有利於正則表達式(儘管Java的特定實現似乎對來自經驗的數百種模式進行了曠日持久的表現)。 – PSpeed 2010-02-25 03:33:46

+1

對於非文字模式,匹配本身很昂貴,它可能會支付運行幾個單獨的操作,而不是一個大的正則表達式...尤其是如果你不關心最早的匹配(位置明智)。 – PSpeed 2010-02-25 03:34:37

1

我強烈建議您編寫代碼,併爲它編寫代碼。這很簡單,你會得到一個不是通用的「經驗法則」的答案,而是一個非常具體的答案,適用於你的問題領域。

萬斯·莫里森大約有微標杆優良的帖子,有一個工具,使得它可以很簡單的爲您解答這樣的問題......

http://msdn.microsoft.com/en-us/magazine/cc500596.aspx

如果你想我個人的「規則拇指「,那麼正是這種RegEx往往比較慢,但你應該忽略我,並自己測量:-)

如果由於非性能原因,你繼續使用正則表達式,那麼我可以真正推薦兩件事情。獲取分析器(例如ANTS)並查看代碼在生產中的作用。然後,獲得正則表達式食譜的副本...

http://www.amazon.co.uk/Regular-Expressions-Cookbook-Jan-Goyvaerts/dp/0596520689/ref=sr_1_1?ie=UTF8&s=books&qid=1259147763&sr=8-1

...因爲它有技巧的負荷關於加快正則表達式的代碼。根據本書的技巧,我已經將RegEx代碼優化了10倍。

+0

我很高興聽到你喜歡正規表達式食譜。如果您的任何朋友還沒有副本,O'Reilly和我在regexguru.com上做了一個贈品,任何人都可以參加,直到本月底(2010年2月28日)。 – 2010-02-25 02:16:08

+0

@Jay酷。我會轉發這件事。感謝您的回饋。 – 2010-02-25 17:01:49

3

如果不使用探查器很難估計性能,通常最好的策略是編寫最符合邏輯的概念,並且易於理解/閱讀。如果兩個.contains()調用在邏輯上更容易理解,那麼這是更好的路線,如果正則表達式更有意義,則同樣的邏輯適用。

考慮到團隊中的其他開發人員可能對正則表達式沒有很好的理解也很重要。如果在生產中稍後使用正則表達式覆蓋.contains()(或反之亦然),則將其識別爲瓶頸,請嘗試並分析這兩者。經驗法則:編寫代碼以便讀取,使用探查器識別瓶頸,然後用更快的代碼替換可讀代碼。

+0

+1不要過早優化。 – 2009-11-25 11:58:47

3

RegexBuddy有一個內置的正則表達式調試器。它顯示了正則表達式引擎需要多少步才能找到匹配項或找不到匹配項。通過在不同長度的字符串上使用調試器,您可以瞭解正則表達式的複雜性(大O)。如果你在RegexBuddy的幫助文件的索引中查找「基準」,你會得到一些關於如何解釋這個問題的提示。

當判斷正則表達式的性能時,測試正則表達式失敗以查找匹配的情況尤其重要。編寫一個在線性時間內找到匹配的正則表達式非常容易,但是在我稱之爲catastrophic backtracking的情況下,指數時間失敗。

要使用5 if語句作爲一個例子,當遇到one|two|three|four|five掃描一次輸入字符串正則表達式,做額外的工作一點點的ot,或者f。但是,如果語句檢查字符串是否包含一個單詞,則將搜索整個字符串5次,如果找不到任何單詞。如果five發生在字符串的開頭,那麼正則表達式立即找到匹配,而前5個if語句在第5個if語句找到匹配之前掃描整個字符串是徒勞的。