2016-05-15 79 views
1

找不到適合這種數學表達式的模式:2*-5+ sin(1.5*4)+(28- 3^4-(cos(3+(19*3)+1+(6/2))/2+tan(1+cos(1+9))-6/3+2.3*3.3345)+1)+1)-(4/2)其中有(或不是) cos的內部括號。 理想的結果是:正則表達式的cos/sin/tan與內部括號內

1. cos(3+(19*3)+1+(6/2)) 
2. cos(1+9) 

我試圖cos\(.+?\),但我只得到cos(3 + (19*3)。如果我正在嘗試一個貪婪的量詞,我得到整個字符串直到最後一個)

謝謝你提前!

+0

代數表達式不是一種常規語言。使用合適的解析器。 – hop

+0

http://stackoverflow.com/a/5475880/5812121 – timolawl

+1

那麼,[當前重複](http://stackoverflow.com/questions/5475804)/regular-expression-for-math-operations-with-brackheses)問題涉及表達式中的任何''單元,而這個問題只問如何得到單位'cos(...)'。 –

回答

1

我會建議一種方法接受字符串解析,在起始平衡符號之前的字符串,字符分隔符和包含或排除分隔符(標記)的標誌。

Java IDEONE demo

public static List<String> getBalancedStr(String s, String strBefore, Character markStart, 
           Character markEnd, Boolean includeMarkers) { 
    Matcher m = Pattern.compile("(?=(\\b\\Q" + strBefore + markStart.toString() + "\\E.*))").matcher(s); 
    List<String> subTreeList = new ArrayList<String>(); 
    while (m.find()) { 
     int level = 0; 
     int lastOpenBracket = -1; 
     for (int i = 0; i < m.group(1).length(); i++) { 
      char c = m.group(1).charAt(i); 
      if (c == markStart) { 
       level++; 
       if (level == 1) { 
        lastOpenBracket = (includeMarkers ? i : i + 1); 
       } 
      } 
      else if (c == markEnd) { 
       if (level == 1) { 
        if (includeMarkers) { 
         subTreeList.add(strBefore + m.group(1).substring(lastOpenBracket, i + 1)); 
        } else { 
         subTreeList.add(m.group(1).substring(lastOpenBracket, i)); 
        } 
        break; 
       } 
       level--; 
      } 
     } 
    } 
    return subTreeList; 
} 

使用範例:

String s = "2*-5+ sin(1.5*4)+(28- 3^4-(cos(3+(19*3)+1+(6/2))/2+tan(1+cos(1+9))-6/3+2.3*3.3345)+1)+1)-(4/2)"; 
System.out.println("cos: " + getBalancedStr(s, "cos", '(', ')', true)); 
// cos: [cos(3+(19*3)+1+(6/2)), cos(1+9)] 
System.out.println("sin: " + getBalancedStr(s, "sin", '(', ')', true)); 
// sin: [sin(1.5*4)] 
System.out.println("tan: " + getBalancedStr(s, "tan", '(', ')', true)); 
// tan: [tan(1+cos(1+9))] 

注意,這個方法編譯正則表達式 - "(?=(\\b\\Q" + strBefore + markStart.toString() + "\\E.*))" - 將匹配cos或者只是作爲一個完整的單詞sin(因爲\b是一個字的邊界)和.*將匹配到行的末尾。如果您想要支持多行輸入,請在前面使用(?s)"(?s)\\b\\Q" + strBefore + markStart.toString() + "\\E.*"。由於該模式位於未錨定的積極預測中的捕獲組中,因此我們收集所有重疊匹配,並且每次匹配只會得到1個平衡子串(因爲在找到相應的匹配結束分隔符後,我們跳出for循環。