Android簡易計算機(四)-完全な論理コード

19792 ワード

最近、アンドロイドに関する知識を学んでいます.最初のdemoは簡易計算機を作りました.携帯電話に付属している計算機を真似ています.括弧をつけず、簡単な4つの演算で、長表現式の演算をサポートしています.このページには、今回の簡易計算機の完全な論理コードが貼られています.
コードは次のとおりです.
package com.example.zwkkkk1.caculator1;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.math.BigDecimal;
import java.util.Stack;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static String TAG = "CACULATOR";
    TextView txt_result, txt_edit;
    boolean isOperateDown = false;//           ,       false
    boolean isDotDown = false;//.         ,       false
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txt_edit = (TextView)findViewById(R.id.txt_edit);
        txt_result = (TextView)findViewById(R.id.txt_result);

        findViewById(R.id.btn_0).setOnClickListener(this);
        findViewById(R.id.btn_1).setOnClickListener(this);
        findViewById(R.id.btn_2).setOnClickListener(this);
        findViewById(R.id.btn_3).setOnClickListener(this);
        findViewById(R.id.btn_4).setOnClickListener(this);
        findViewById(R.id.btn_5).setOnClickListener(this);
        findViewById(R.id.btn_6).setOnClickListener(this);
        findViewById(R.id.btn_7).setOnClickListener(this);
        findViewById(R.id.btn_8).setOnClickListener(this);
        findViewById(R.id.btn_9).setOnClickListener(this);
        findViewById(R.id.btn_divide).setOnClickListener(this);
        findViewById(R.id.btn_multi).setOnClickListener(this);
        findViewById(R.id.btn_plus).setOnClickListener(this);
        findViewById(R.id.btn_sub).setOnClickListener(this);
        findViewById(R.id.btn_equal).setOnClickListener(this);
        findViewById(R.id.btn_clear).setOnClickListener(this);
        findViewById(R.id.btn_back).setOnClickListener(this);
        findViewById(R.id.btn_equal).setOnClickListener(this);
        findViewById(R.id.btn_dot).setOnClickListener(this);
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_0:
                num_down("0");break;
            case R.id.btn_1:
                num_down("1");break;
            case R.id.btn_2:
                num_down("2");break;
            case R.id.btn_3:
                num_down("3");break;
            case R.id.btn_4:
                num_down("4");break;
            case R.id.btn_5:
                num_down("5");break;
            case R.id.btn_6:
                num_down("6");break;
            case R.id.btn_7:
                num_down("7");break;
            case R.id.btn_8:
                num_down("8");break;
            case R.id.btn_9:
                num_down("9");break;
            case R.id.btn_plus:
                operator_down("+");break;
            case R.id.btn_sub:
                operator_down("-");break;
            case R.id.btn_divide:
                operator_down("÷");break;
            case R.id.btn_multi:
                operator_down("×");break;
            case R.id.btn_clear:
                isDotDown = false;
                isOperateDown = false;
                txt_edit.setText("0");
                txt_result.setText("");
                break;
            case R.id.btn_back: {
                String strEdit = txt_edit.getText().toString();
                int length = strEdit.length();
                if (Pattern.matches("^=[0-9].*", strEdit)) {
                    txt_edit.setText("0");
                    txt_result.setText("");
                } else {
                    if (length > 0) {
                        String word = strEdit.substring(length - 1, length);
                        if(word.equals("."))
                            isDotDown = false;
                        if(word.equals("+") || word.equals("-") || word.equals("×") || word.equals("÷"))
                            isOperateDown = false;
                        txt_edit.setText(strEdit.substring(0, length - 1));
                    }
                }
                break;
            }
            case R.id.btn_dot: {
                String strEdit = txt_edit.getText().toString();
                if (!isDotDown) {
                    isDotDown = true;
                    if(Pattern.matches("^=[0-9].*", strEdit))
                        strEdit = "0";
                    txt_edit.setText(strEdit + ".");
                }
                break;
            }
            case R.id.btn_equal:
                equal();break;
        }
    }

    //      
    private void num_down(String num) {
        String strEdit = txt_edit.getText().toString();
        isOperateDown = false;

        if (strEdit.equals("0") || Pattern.matches("^=[0-9].*", strEdit)) {
            txt_edit.setText(num);
            txt_result.setText("");
        } else {
            txt_edit.setText(strEdit + num);
        }
    }

    //        
    private void operator_down(String operator) {
        if(!isOperateDown) {
            String strEdit = txt_edit.getText().toString();
            isOperateDown = true;
            isDotDown = false;
            if(Pattern.matches("^=[0-9].*", strEdit))
                strEdit = strEdit.substring(1, strEdit.length());
            txt_edit.setText(strEdit + operator);
        }
    }

    private void equal() {
        String strEdit = txt_edit.getText().toString();
        int length = strEdit.length();
        if(!Pattern.matches("^=[0-9].*", strEdit))
        {
            txt_result.setText(strEdit);
            if(Pattern.matches(".*[\\+\\-\\×\\÷\\.]$", strEdit)) {
                strEdit = strEdit.substring(0, length - 1);
            }
            String postfixExp = getPostfixExp(strEdit);
            txt_edit.setText("=" + calPostfix(postfixExp));
        }
    }


    //              
    private String getPostfixExp(String str) {
        String postfix = "";
        String numString = "";   //          String  
        Stack numStack = new Stack();
        Stack opStack = new Stack();
        for(int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if(Character.isDigit(ch) || ch == '.') {    //  ch           .
                numString += String.valueOf(ch);        //     .  numString,        
            } else {    //ch     
                if(numString.length() > 0) {
                    numStack.push(numString);//             
                    numString = "";         //    ,    numString
                }
                opPush(opStack, numStack, ch);
            }
        }

        //    numString    ,           ,         
        if(numString.length() > 0)
            numStack.push(numString);

        //    ,             
        while(!opStack.empty()) {
            numStack.push(opStack.pop());
        }
        //               
        //          ,        ,         ,      reverse      
        //            ,      
        while(!numStack.empty()) {
            opStack.push(numStack.pop());
        }
        while(!opStack.empty()) {
            postfix = postfix + String.valueOf(opStack.pop()) + " ";
        }
        return postfix;
    }

    //       
    private String calPostfix(String str) {
        String result = "";
        Stack numStack = new Stack();
        for(int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if(ch == ' ') {
                //    
                if(result.length() > 0 && (result.equals("+") || result.equals("-") || result.equals("×") || result.equals("÷")))
                {
                    double num = 0;
                    double secondNum = Double.parseDouble(String.valueOf(numStack.pop()));
                    double firstNum = Double.parseDouble(String.valueOf(numStack.pop()));
                    switch (result) {
                        case "+":
                            num = firstNum + secondNum;break;
                        case "-":
                            num = firstNum - secondNum;break;
                        case "×":
                            num = firstNum * secondNum;break;
                        case "÷":
                            num = firstNum / secondNum;break;
                    }
                    numStack.push(num);
                }
                else if(result.length() > 0) {
                    numStack.push(result);
                }
                result = "";
            } else {
                result += String.valueOf(ch);
            }
        }
        return BigDecimal.valueOf(Double.valueOf(String.valueOf(numStack.pop()))).stripTrailingZeros().toPlainString();
    }
    //       
    private int getOpWeight(char ch) {
        // + -    1
        if(ch == '+' || ch == '-') return 1;
        //× ÷    2
        if(ch == '×' || ch == '÷') return 4;
        return -1;
    }

    //       
    private void opPush(Stack opStack, Stack numStack, char ch) {
        if(canOpPush(opStack, ch)) {    //            
            opStack.push(ch);           //true     
        } else {                        //false(            <=         )
            //             
            numStack.push(String.valueOf(opStack.pop()));
            //        ,        >=          
            opPush(opStack, numStack, ch);
        }
    }

    //             
    private Boolean canOpPush(Stack opStack, char ch) {
        //        ,  true;                ,  true
        if(opStack.empty() || (getOpWeight(ch) > getOpWeight(String.valueOf(opStack.peek()).charAt(0))))
            return true;

        return false;           //      false
    }
}