iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
0
自我挑戰組

跟Kotlin一起來聊Android元件 或許還有應用,或許還有一些資訊雜談系列 第 15

將字串運算式轉成運算結果

今天其實想要回歸單純的程式設計思考。

之前被人問過簡單的計算機要怎麼設計。

首先想到的就是計算流程是怎麼樣的

  • 是輸入數字遇到運算子就執行計算,one way ticket模式
  • 還是要等運算的描述先輸入完成,直到輸入等號再進行運算

第一項其實很直覺的就是建立一個變數儲存計算後的值,遇到運算子時記錄,等待下一個運算元輸入後進行計算。
舉例來說 :

  1. 輸入5
    [保存區 運算子區 輸入區 5 ]
  2. 輸入+,將5存至保存區,記錄運算子類型
    [保存區 5 運算子區 + 輸入區 ]
  3. 輸入1,將保存區的值根據運算子類型與當下輸入的值作運算 5+1 存至保存區
    [保存區 6 運算子區 輸入區 ]
  4. 判斷下一個動作...

就是直接看要處理的是運算子還是運算元進行處理,所以就不多說了。

第二項由於是包含整個完整的語意流程,我們需要判斷的事情就比較多了。像是

  • 先乘除後加減的規則
  • 處理數字與運算子的動作

當我們遇到有一串字串要計算,像是"10+0.5X2-7+15/3",可以透過自訂函式直接將字串轉成運算結果。

概念是透過解析字串將數字與運算符號分開,再作運算。

  • 這時候就需要兩個列表來存儲數字與運算子
  • 並且判斷運算子列表的優先權(乘除 > 加減)來決定哪些數字要優先處理

當找到乘除等優先權高的運算子,去找出對應的數字並且取出作完運算後存回列表,繼續流程直到沒有運算子,或是只剩下一個運算元。

例 : "10+0.5X2-7+15/3"
數字列表 :  10,0.5,2,7,15,3
運算子列表 : +,x,-,+,/

第一步

  • 先找到第一個優先權高的x,
  • 找出對應的數字0.5跟2,
  • 進行運算後數字列表 刪除0.5,2回存1,
  • 運算子列表刪除X

數字列表 :  10,1,7,15,3
運算子列表 : +,-,+,/

第二步

  • 找到第一個優先權高的/,
  • 找出對應的數字15跟3,
  • 進行運算後數字列表 刪除15,3回存5,
  • 運算子列表刪除/

數字列表 :  10,1,7,5
運算子列表 : +,-,+

第三步

  • 找到第一個優先權高的+,
  • 找出對應的數字10跟1,
  • 進行運算後數字列表 刪除10,1回存11,
  • 運算子列表刪除+

數字列表 :  11,7,5
運算子列表 : -,+

第四步

  • 找到第一個優先權高的-,
  • 找出對應的數字11跟7,
  • 進行運算後數字列表 刪除11,7回存4,
  • 運算子列表刪除-

數字列表 :  4,5
運算子列表 : +

第五步

  • 找到第一個優先權高的+,
  • 找出對應的數字4跟5,
  • 進行運算後數字列表 刪除4,5回存9,
  • 運算子列表刪除+

數字列表 :  9
運算子列表 :

達到條件 :沒有運算子,或是只剩下一個運算元,回傳9

先上程式碼

   fun eval(strins:String) :Float{
        var changeString=strins
        var logiclist= arrayListOf<String>()
        var numberlist =arrayListOf<Float>()
        var appendString=""
        for(i in 0 until changeString.length){
            if(!changeString[i].isDigit() && changeString[i]!='.') {
                logiclist.add(changeString[i].toString() )
                numberlist.add(appendString.toFloat())
                appendString=""
            }
            else if(i<changeString.length-1){
                 appendString+=changeString[i]
            }
            else{
                appendString+=changeString[i]
                numberlist.add(appendString.toFloat())
            }
        }
        while(logiclist.size>0 && numberlist.size>1){
        //先乘除
            var countFirstIndex=logiclist.indexOfFirst { it ->it=="*" || it=="/" }
            var countingA :Float
            var countingB :Float
            if(countFirstIndex>=0){
                countingA=numberlist[countFirstIndex]
                countingB=numberlist[countFirstIndex+1]
                var temp:Float= 0F
                when(logiclist[countFirstIndex]){
                    "*"->{
                        temp=countingA*1F * countingB*1F
                    }
                    "/"->{
                        temp=(countingA*1F / countingB*1F)
                    }
                }
                numberlist.removeAt(countFirstIndex)
                numberlist.removeAt(countFirstIndex)
                logiclist.removeAt(countFirstIndex)
                numberlist.add(countFirstIndex,temp)
            }
            else{
            //後加減
                var countIndex=logiclist.indexOfFirst { it ->it=="+" || it=="-" }
                countingA=numberlist[countIndex]
                countingB=numberlist[countIndex+1]
                if(countIndex>=0){
                    var temp:Float= 0F
                    when(logiclist[countIndex]){
                        "+"->{
                            temp=countingA*1F + countingB*1F
                        }
                        "-"->{
                            temp=(countingA*1F - countingB*1F)
                        }
                    }
                    numberlist.removeAt(countIndex)
                    numberlist.removeAt(countIndex)
                    logiclist.removeAt(countIndex)
                    numberlist.add(countIndex,temp)
                }
            }
        }
        return numberlist[0]
    }

由於只是將邏輯實現,程式碼部分並沒有作優化。


上一篇
來用EditView信仰之躍,資料輸入後直接跳到下一個EditView輸入
下一篇
來用Anko SQLite 使用ManagedSQLiteOpenHelper實作SQL模板
系列文
跟Kotlin一起來聊Android元件 或許還有應用,或許還有一些資訊雜談30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言