可以解析公式的java類執行個體--可傳入數值運算運算式、含變數的運算運算式

來源:互聯網
上載者:User

 前幾天遇到一個問題,需要從xml檔案裡讀取一個含參數的公式並調用它。

   於是上網找方法,但是實在是沒有找到可以解析含參數的公式的方法,於是吸取了一些精華,並在此基礎上加以改造,終於實現了,但是這樣的效率很低,如果誰有更好的辦法,希望拿出來分享,我在此算是拋磚引玉吧~~

    測試類別在最底下, 可以根據自己的需求進行測試。

    可以將此類作為一個工具類, 在其他類調用的時候只需調用其構造方法以及getResult()方法(詳細見本例main方法)。如果在其他類需要使用含有參數的公式,可以利用Formula.paras.add(“要加入的資料”)方法存入資料,該類在提取資料的時候預設是按存入的順序取,也就是說第一個變數的值是存入的第一個資料(見本例),以此類推。


以下為代碼-----------------------------------------------------------------------------------------------------------------------------------------------------------

import java.util.Vector;
public class Formula {
    private int leftBracket = 0; //左括弧個數
    private int rightBracket = 0;//右括弧個數
    private int startL = 0;//左括弧的位置
    private int startR = 0;//右括弧的位置
    private double answer = 0;
    private String leftNumber = "0";
    private String rightNumber = "0";
    public String Msg = "";
    private String formula="";
    private int[] sym = new int[4];
    private Vector<String> list = new Vector<String>();//用來存放從字串解析出來的字元
    static Vector<Integer> paras = new Vector<Integer>();//用來存放變數參數


    /*
     *構造方法,以要算的公式為參數 
     */
    public Formula(String calRule){
      this.setFormula(calRule);
    }
    
    /*
     * 獲得左括弧數
     */
    private int getLeftBracket(String calRule) {
        leftBracket = 0;
        startL = calRule.indexOf("(");
        if (startL != -1) {
            calRule = calRule.substring(startL + 1, calRule.length());
        }
        while (startL != -1) {
            leftBracket++;
            startL = calRule.indexOf("(");
            calRule = calRule.substring(startL + 1, calRule.length());
        }
        return leftBracket;
    }


    /*
     * 設定格式
     */
    public void setFormula(String calRule){
      formula=replaceSubtration(calRule.trim());
      formula="("+formula+")";
    }
    
    /*
     * 為了使公式中支援負數,使用“`”表示減號,使用“-”表示負號,把所有減號換成“‘”
    */
    private String replaceSubtration(String vstr){
      String tmp="";
      String result="";
      int startS = vstr.indexOf("-");
      if (startS !=-1) {
        if (startS > 0) {
          tmp = vstr.substring(startS - 1, startS);
          if (!"+".equals(tmp) && !"-".equals(tmp) && !"*".equals(tmp) &&!"/".equals(tmp) &&
             !"(".equals(tmp)){
            result = result + vstr.substring(0, startS) + "`";
          }
          else
            result = result + vstr.substring(0, startS + 1);
        }
        else
          result = result + vstr.substring(0, startS + 1);
       vstr = vstr.substring(startS + 1);
      }
      while (startS != -1) {
        startS = vstr.indexOf("-");
        if (startS > 0) {
          tmp = vstr.substring(startS - 1, startS);
          if (!"+".equals(tmp) && !"-".equals(tmp) && !"*".equals(tmp) &&!"/".equals(tmp) &&
             !"(".equals(tmp))
            result = result + vstr.substring(0, startS) + "`";
          else
            result = result + vstr.substring(0, startS + 1);
        }
        else
          result = result + vstr.substring(0, startS + 1);
          vstr = vstr.substring(startS + 1);
      }
      result+=vstr;
      return result;
    }


    public String getFormula(){
      return formula.replace('`','-').substring(1,formula.length()-1);
    }


    /*
     * 獲得右括弧數
     */
    private int getRightBracket(String calRule) {
        rightBracket = 0;
        startR = calRule.indexOf(")");
        if (startR != -1) {
            calRule = calRule.substring(startR + 1, calRule.length());
        }
        while (startR != -1) {
            rightBracket++;
            startR = calRule.indexOf(")");
            calRule = calRule.substring(startR + 1, calRule.length());
        }
        return rightBracket;
    }


    /*
    /*對比左右括弧個數
    */
    private boolean compareToLR() {
        int lb = getLeftBracket(formula);
        int rb = getRightBracket(formula);
        boolean CTLR = false;
        if (lb == rb) {
            Msg = "";
            CTLR = true;
        } else if (lb > rb) {
            Msg = "左括弧的個數多於右括弧,請檢查。";
            CTLR = false;
        } else {
            Msg = "左括弧的個數少於右括弧,請檢查。";
            CTLR = false;
        }
        return CTLR;
    }
   /*
   /*檢查公式中是否存在非法字元如(+、-)等
   */
   private boolean checkFormula(){
      boolean isOk=true;
      String[] bracket =new String[2];
      String[] sign=new String[4];
      bracket[0]="(";
      bracket[1]=")";
      sign[0]="+";
      sign[1]="`";
      sign[2]="*";
      sign[3]="/";
      String vstr="";
      for(int i=0;i<bracket.length;i++){
        for(int j=0;j<sign.length;j++){
          if (i==0)
            vstr=bracket[i]+sign[j];
          else
            vstr=sign[j]+bracket[i];
          if (formula.indexOf(vstr)>0){
            Msg="公式中存在非法字元"+vstr;
            isOk=false;
            return isOk;
          }
        }
      }
      for(int i=0;i<sign.length;i++){
        for(int j=0;j<sign.length;j++){
          vstr=sign[i]+sign[j];
          if (formula.indexOf(vstr)>0){
              Msg="公式中存在非法字元"+vstr;
              isOk=false;
              return isOk;
          }
        }
      }
      if (formula.indexOf("()")>0){
        Msg="公式中存在非法字元()";
        isOk=false;
      }
      return isOk;
    }
   
   /*
    *判斷輸入的字串是否合法
    */
   public boolean checkValid(){
     if ((formula==null) || (formula.trim().length()<=0) ) {
       Msg="請設定屬性calRule!";
       return false;
     }
     return (compareToLR()&&checkFormula());
   }


  /*返回公式執行結果
  */
  public double getResult(){
String formulaStr = "", calRule = "";
double value = 0.0;
calRule = this.formula;
if (checkValid()) {
  for (int i = 0; i < leftBracket; i++) {
    int iStart=calRule.lastIndexOf("(") + 1;
    //獲得最裡層括弧裡的內容
    formulaStr = calRule.substring(iStart, iStart+calRule.substring(iStart).indexOf(")")).trim();
    symbolParse(formulaStr);
    value = parseString();
    iStart=calRule.lastIndexOf("(");
    int iEnd=calRule.substring(iStart).indexOf(")")+1;
    calRule = calRule.substring(0,iStart).trim() +
        value +
        calRule.substring(iStart+iEnd, calRule.length()).trim();
  }
}
double tmp = Math.pow(10, 10);
value = Math.round(value * tmp) / tmp;
System.out.println(Msg);
return value;
   }
    public void FormulaStr(String calRule) {
        String formulaStr = "";
        if (checkValid()) {
            for (int i = 0; i < leftBracket; i++) {
                formulaStr = calRule.substring(calRule.lastIndexOf("(") + 1, calRule.indexOf(")")).trim();
                symbolParse(formulaStr);
                double value = parseString();
                String.valueOf(value);
                System.out.println("formulaStr=" + formulaStr);
                //formulaVal = Double.parseDouble(formulaStr);
                System.out.println("formulaVal=" + value);
                calRule = calRule.substring(0, calRule.lastIndexOf("(")).trim() + value + calRule.substring(calRule.indexOf(")") + 1,                                                       calRule.length()).trim();
                System.out.println("calRule=" + calRule);
            }
        }
    }


    /*
    /*抽取最終括弧內資料到List
    */
    private void symbolParse(String str) {
        list.clear();
        int count = 0;
        for (int i = 0; i < 4; i++) {
            compareMin(str);
            while (sym[i] != -1) {
                String insStr = str.substring(0, sym[i]).trim();
                //判斷insStr是否含有字母
if(containsLetter(insStr)) {
insStr = Integer.toString(parseLetter(insStr, paras.get(count)));
}
                list.add(insStr);
                insStr = str.substring(sym[i], sym[i] + 1).trim();
                list.add(insStr);
                
                str = str.substring(sym[i] + 1, str.length()).trim();
                compareMin(str);
                count++;
            }
        }
        if (sym[0] == -1 && sym[1] == -1 && sym[2] == -1 & sym[3] == -1) {
if(containsLetter(str)) {
str = Integer.toString(parseLetter(str, paras.get(count)));
}
            list.add(str);
        }
    }
    
    public boolean containsLetter(String insStr) {
    boolean isLetter = false;
    
    for(int i=0; i<insStr.length(); i++) {
    char ch = insStr.charAt(i);
    if(Character.isLetter(ch)) {
    isLetter = true;
    }
    }
    return isLetter;
    }
    
    public int parseLetter(String insStr, int para) {
    
    if(insStr.charAt(0) == '-') {
    para = 0-para;
    }
    return para;
    }
    
     /*
    /*迴圈比較賦SubString起始值
    */
    private void compareMin(String str) {
        int sps = str.indexOf("`");//減法subtration
        sym[0] = sps;
        int spa = str.indexOf("+");//加法addition
        sym[1] = spa;
        int spd = str.indexOf("/");//除法division
        sym[2] = spd;
        int spm = str.indexOf("*");//乘法multiplication
        sym[3] = spm;
        for (int i = 1; i < sym.length; i++) {
            for (int j = 0; j < sym.length - i; j++)
                if (sym[j] > sym[j + 1]) {
                    int temp = sym[j];
                    sym[j] = sym[j + 1];
                    sym[j + 1] = temp;
                }
        }
    }


    private double parseString()
            throws NumberFormatException, StringIndexOutOfBoundsException {
        try{
          calculate();
          return answer;
        }catch(Exception e){
          Msg="錯誤:" + e.getMessage();
          return 0.0;
        }
    }


    /*
     * 計算
     */
    private void calculate() {
        /*
        /*處理除法
        */
        int spd = list.indexOf("/");

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.