2013-01-03 54 views
6

我想在Java中製作一個函數圖形化程序,它涉及到用戶輸入的函數將被繪製,分析和繪製它。例如,用戶可以輸入x^2 - y^2,cos(x + y),log(x) - sqrt(y)等。該程序使用中綴二進制運算(+, - 等) )和一元運算(cos,sqrt等)。Java的正則表達式性能問題

總之,爲了評估一元運算,我必須確保給定的表達式遵循單一一元運算的格式。例如,cos(x),sqrt(x + y)和log(exp(y) - x)都適合這種格式,因爲它們是以一些表達式作爲操作數的一元操作。然而,諸如sin(x)* cos(y)和1 + log(x)之類的字符串不遵循這種格式。爲了檢查,我做了此格式的正則表達式:

String unaryName = "((productlog)|(zeta)|(log)|(sqrt)|(cos)|(sin)|(tan)|(sec)|(csc)|(csc)|(abs)|(arccos)|(arcsin)|(arctan)|(arcsec)|(arccsc)|(arccot)|(gamma)|(exp))"; 

(這僅僅是一個正則表達式來檢查,如果給定的字符串是一個預定義的一元運算的名稱)

String unaryOperation = unaryName + "\\(([^\\(\\)]*(\\(.*\\))*[^\\(\\)]*)+\\)" 

我我會解釋一下。這個正則表達式正在尋找一個一元操作的名字。之後,它會查找左括號。之後,它會查找一些不是括號的字符序列,然後是一些以左括號開頭並以右括號結尾的序列。後者防止諸如「sin(x)+ cos(y)」之類的字符串匹配。

這個正則表達式總是給出想要的結果,據我所知。但是,在使用時出現一個問題。考慮這種情況:

String s = "cos(3) + sin(4)"; 
System.out.println(s.matches(unaryOperation)); 

顯然,如果正則表達式的作品,應返回false,這確實。這個例子也是如此:

String s = "cos(3.000) + sin(4)"; 
System.out.println(s.matches(unaryOperation)); 

沒有真正改變,模式明智。然而,在3中連續增加0,這場比賽似乎要以指數級的時間來評估。對我而言,12個零點需要大約13秒。由於我的程序將繪製圖表上的許多點,因此每次繪製圖形時都需要計算數以千計的表達式,所以這是一個致命的缺陷。

我已經找到了一種方法來使用這個正則表達式,我的程序工作得非常好,但我仍然想知道:爲什麼這個正則表達式需要這麼長時間才能處理大量輸入,並且在那裏任何方式來改變正則表達式來解決這個問題?

+1

你爲什麼要用正則表達式解析表達式? –

回答

1

你可以使用這個表達式

unaryName+"\\([^)]*(\\([^()]*\\))?[^(]*\\)" 
        ------------ 
         |->starting from center. 

在這裏,我檢查圓括號是否正確平衡 ..That應該解決您的問題!

+0

使用'String.matches'時不需要錨點。 –

+0

謝謝!我唯一的疑慮是你的正則表達式與cos(x)不匹配,或者沒有嵌套括號的任何一元運算,但是很容易修復:unaryName +「\\([^)] *(\\([^()] * \\))* [^(] * \\)$「 – MikeB

+0

@MikeB您需要使用'?'而不是'*',因爲答案爲 – Anirudha

0

我懷疑問題是你的表情正在做一個很多的回溯,因爲.*在模式中。嘗試用一個不情願的量詞替換它:.*?或者更好(如果我理解邏輯),用[^\\)]*

其實,就不會這樣做的伎倆:

String unaryOperation = unaryName + "\\([^\\)]*\\)"; 

這看起來對於一個名稱,一個左括號,任何數量的非右括號字符,然後一個右括號。這假定你不想匹配像

"cos(3 * (4 + x))" 

(你的模式也不會匹配)。

+0

我做到了,仍然需要10秒。略有改善,但仍然不足。編輯 - 也嘗試了第二個建議,也沒有工作。 – MikeB

+0

@MikeB - 我在編輯中提供了另一個建議。 –

+0

我確實想要匹配cos(3 +(4 + x))之類的東西,而且我相信我的原始正則表達式確實符合這一點。 – MikeB