趙素萍,胡雪鋒,賀 強(qiáng)
(晉中信息學(xué)院大數(shù)據(jù)信息工程學(xué)院,晉中 030800)
傳統(tǒng)的計(jì)算器項(xiàng)目中,表達(dá)式計(jì)算一般采用棧的數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn),即當(dāng)用戶(hù)輸入一個(gè)數(shù)、輸入一個(gè)運(yùn)算符,輸入的數(shù)壓入num棧,輸入的運(yùn)算符壓入op棧。每次輸入的運(yùn)算符在壓棧之前,都需要判斷op棧是否為空,為空則入棧,不為空則進(jìn)行如下操作:
(1)判斷棧頂元素與當(dāng)前運(yùn)算符的優(yōu)先級(jí),若棧頂元素的優(yōu)先級(jí)高,則進(jìn)行(2),否則執(zhí)行步驟3。
(2)需要先從num棧彈出兩個(gè)元素,從op棧彈出一個(gè)元素進(jìn)行計(jì)算,后將計(jì)算結(jié)果壓入num棧,轉(zhuǎn)入(1)繼續(xù)循環(huán)判斷。
(3)運(yùn)算符壓棧,繼續(xù)后續(xù)操作。
符號(hào)棧為空時(shí),num棧只有一個(gè)元素,即為運(yùn)算結(jié)果,直接輸出即可。
該方法的局限性是要求操作數(shù)只能是一位,若要實(shí)現(xiàn)多位數(shù)的運(yùn)算需要找到上一個(gè)輸入的字符是否為數(shù)值型數(shù)據(jù),且將num出棧并將棧頂元素乘10,加上當(dāng)前輸入的數(shù)再次入棧。本來(lái)使用棧就比較復(fù)雜,現(xiàn)又需要不停的進(jìn)行壓棧和出棧操作,同時(shí)需要將表達(dá)式作為字符串存起來(lái)。刪除操作也較復(fù)雜,需要判斷當(dāng)前刪的是運(yùn)算符還是數(shù),運(yùn)算符可以直接刪除,數(shù)的話(huà)需要判斷數(shù)是幾位數(shù),多位數(shù)需要出棧,除10取整后再入棧。
若直接對(duì)字符串進(jìn)行操作,就可以省去很多入棧出棧的操作。
微信小程序是2017年才開(kāi)始運(yùn)行的,并以飛快的速度發(fā)展壯大。微信小程序有手機(jī)原生APP所不具備的優(yōu)點(diǎn),即無(wú)需安裝、無(wú)需升級(jí)、無(wú)需卸載、不占手機(jī)存儲(chǔ)空間、用完即走。在一些用戶(hù)使用頻率很少的場(chǎng)合,微信小程序發(fā)揮了他的巨大作用。據(jù)不完全統(tǒng)計(jì),僅2020年一年,微信小程序中健康碼的服務(wù)用戶(hù)超過(guò)8億,其中用戶(hù)累計(jì)出示健康碼的次數(shù)則超過(guò)了200億次。正是由于微信小程序用完即走的這一特點(diǎn),用戶(hù)才在僅需要出示健康碼這種低頻事件中使用了微信小程序。而計(jì)算器也是低頻事件,人們僅在很少的時(shí)候需要計(jì)算,完全可以將原生APP替換。
向字符串每輸入一個(gè)數(shù)字,或刪除字符串的最后一個(gè)字符時(shí),都會(huì)將表達(dá)式進(jìn)行分割并計(jì)算。
JavaScript的Split(參數(shù)1,參數(shù)2)函數(shù)會(huì)實(shí)現(xiàn)字符串的分割,參數(shù)1可以是字符串也可以是正則表達(dá)式,由于我們要用的分割字符不是一個(gè),如要求得數(shù)字?jǐn)?shù)組,分割字符分別是‘+’,‘-’,‘*’,‘/’,為了實(shí)現(xiàn)小數(shù)的精準(zhǔn)操作,分割字符還加入了‘.’,當(dāng)用戶(hù)輸入的是‘1.+’時(shí),需要將字符串修改為‘1.0+’或‘1+’。所以此處的參數(shù)1只能是正則表達(dá)式。JavaScript正則表達(dá)式的語(yǔ)法為‘/’開(kāi)始‘/’結(jié)束。由此可見(jiàn),將字符串表達(dá)式分割為數(shù)值型數(shù)組的語(yǔ)法為numbers=express.split(/[+-÷×.]/),分割后的結(jié)果會(huì)存到num數(shù)組中。將表達(dá)式分割為運(yùn)算符數(shù)組的語(yǔ)法為options=express.split(/[d]/),正則表達(dá)式中‘d’表示的是所有的數(shù)字型字符,即0到9,分割后的結(jié)果會(huì)存到運(yùn)算符數(shù)組op?tions數(shù)組中。
分割后的數(shù)組中會(huì)有很多的空字符串的數(shù)組元素,針對(duì)多位數(shù)的分割操作,options數(shù)組中有很多的空格。如數(shù)字12按正則表達(dá)式“/[d]/”分割,因?yàn)椤癬1_2_”中的“_”即為空格,所以options有3個(gè)元素,都為空格,即[‘’,‘’,‘’]。舉例說(shuō)明:如12+34×56,numbers數(shù)組為[‘’,‘12’,‘34’,‘56’,‘’],options數(shù)組為[‘’,‘’,‘+’‘’‘×’,‘’,‘’]。由此可見(jiàn),Numbers數(shù)組只需要將首尾的空格去掉即可,而options數(shù)組不僅要?jiǎng)h除首尾的空格,還需要遍歷數(shù)組所有內(nèi)容,將每一個(gè)空字符串都刪除。
刪除數(shù)組中空字符串使用Array.splice(參數(shù)1,參數(shù)2,參數(shù)3…n)函數(shù),參數(shù)1為數(shù)組中的數(shù)組元素的index值,參數(shù)2為刪除的數(shù)組元素的個(gè)數(shù),剩下的參數(shù)為新插入的數(shù)組元素。
由于numbers數(shù)組好操作,只需要?jiǎng)h除首尾的兩個(gè)空字符串即可。
Options數(shù)組中會(huì)有多個(gè)空字符串,按數(shù)字分割則為_(kāi)1_2_3_4+3_3_。字符串中的_即為so數(shù)組中的空字符串,so為[’,‘’,‘*’,‘+’,‘’],需要去除字符串?dāng)?shù)組中的空字符串,需要注意的是,當(dāng)數(shù)組去掉一個(gè)元素以后,相當(dāng)于后面的內(nèi)容已經(jīng)全部往前移了一個(gè)位置,如果此時(shí)仍讓循環(huán)變量+1,則下一次的循環(huán)項(xiàng)相對(duì)于本次循環(huán)項(xiàng)則前進(jìn)了兩個(gè)位置。舉例說(shuō)明,若so為[‘’,‘’,‘*’,‘+’,‘’],第一次循環(huán)so變?yōu)閇‘’,‘*’,‘+’,‘’],循環(huán)變量的值變?yōu)?,直接對(duì)‘*’這一項(xiàng)進(jìn)行操作,導(dǎo)致so的第一項(xiàng)‘’漏掉了,所以每次刪除掉一個(gè)空字符串?dāng)?shù)組項(xiàng)后,循環(huán)變量需要自減1,具體代碼如下:
得到數(shù)組后即可進(jìn)行計(jì)算了。先取兩個(gè)數(shù)字與一個(gè)運(yùn)算符進(jìn)行計(jì)算,即數(shù)字numbers[i]和numbers[i+1]和options[i],計(jì)算完需要?jiǎng)h除num?bers[i+1]和options[i]。舉例說(shuō)明“3+2*6”,初始值為sn[3,2,6],options[+,*]。首先需要計(jì)算的是乘除運(yùn)算,乘除運(yùn)算需要從左往右計(jì)算,所以使用循環(huán)從左往右判斷,是乘法則先乘,否則先除,取數(shù)字2和6,取運(yùn)算符*進(jìn)行計(jì)算,2變?yōu)?2,刪除6,刪除*,運(yùn)算結(jié)果應(yīng)為num?bers[3,12],options[+]。同前所述,每次在循環(huán)體中刪除元素后,都需要將循環(huán)變量自減1。
其中n1和n2為取出的兩個(gè)數(shù)。當(dāng)運(yùn)算符為‘×’,計(jì)算時(shí)需要使用計(jì)算機(jī)編程語(yǔ)言使用的乘號(hào)‘*’。為了實(shí)現(xiàn)從左到右計(jì)算,并實(shí)現(xiàn)優(yōu)先級(jí),所以需要從左到右判斷每一個(gè)字符,先進(jìn)行乘除運(yùn)算,后再進(jìn)行加減運(yùn)算。代碼與乘除相識(shí),只是運(yùn)算符不同而已。
最后當(dāng)numbers數(shù)組只有一個(gè)數(shù)組元素時(shí),只需要將該元素顯示在顯示屏上即可。
為了更好的觀察計(jì)算機(jī)的計(jì)算過(guò)程,在每次計(jì)算時(shí)都在console控制臺(tái)將數(shù)組顯示出來(lái),如表達(dá)式“2-3×5÷8”,先計(jì)算3×5,刪除5和運(yùn)算符×,將3修改為15。再計(jì)算15÷8,刪除8與運(yùn)算符÷,修改15為1.875。最后計(jì)算2-1.875,最后結(jié)果為0.125。刪除運(yùn)算符-。當(dāng)options數(shù)組為空即可停止運(yùn)算輸出顯示結(jié)果。
該功能的實(shí)現(xiàn)應(yīng)用的主要技術(shù)是數(shù)據(jù)綁定,在微信小程序中,數(shù)據(jù)綁定的語(yǔ)法是{{ex?press}},其中express可以是普通的變量,可以是條件、屬性、關(guān)鍵字等。數(shù)據(jù)綁定常用的場(chǎng)合主要分為顯示結(jié)果和改變樣式兩種:
如表達(dá)式的顯示效果,用戶(hù)每單擊一個(gè)按鈕都會(huì)改變表達(dá)式的值。index.wxml文件中在需要顯示的地方添加代碼{{express}}。index.js文件中在data的屬性值區(qū)域添加變量express,并賦初始值。當(dāng)用戶(hù)單擊按鈕時(shí)修改該變量的值,需要注意的是,若要實(shí)現(xiàn)數(shù)據(jù)綁定,不能通過(guò)簡(jiǎn)單的賦值表達(dá)式達(dá)到想要的效果,需要使用setData(參數(shù))函數(shù)實(shí)現(xiàn),其中參數(shù)為json格式的對(duì)象類(lèi)型,即鍵值對(duì)。具體代碼為:this.set?Data({express:之前的表達(dá)式+n}),其中n為用戶(hù)當(dāng)前按鈕傳遞給后臺(tái)的值。
數(shù)據(jù)綁定的內(nèi)容可采用三元表達(dá)式,index.wxml文件中在需要顯示的組件中添加style的屬性值,通過(guò)用戶(hù)在后臺(tái)給isequal變量賦的值來(lái)決定顯示結(jié)果的字體大小,具體代碼如下:style=“font-size:{{isequal?60:(result.length>10?30:50)}}px;”>。其中當(dāng)isequal為真時(shí),字體設(shè)置為60 px,否則如果字符串長(zhǎng)度大,則字體小。同上所述,data中添加isequal變量,并賦初值為false,當(dāng)用戶(hù)單擊等于操作時(shí),通過(guò)setdata方法將該變量賦值為true。需要注意的是,當(dāng)用戶(hù)單擊除了等于號(hào)外的任何按鈕時(shí),都需要將該值修改為false,否則容易出現(xiàn)字體一直變大的狀態(tài)。
通過(guò)不斷的測(cè)試、調(diào)試與維護(hù)。計(jì)算器在手機(jī)上運(yùn)行界面如圖1所示。
圖1 微信小程序計(jì)算器
為了讓讀者更好的看到計(jì)算機(jī)的工作流程,特意將數(shù)組內(nèi)容在控制臺(tái)輸出,如圖2所示。
圖2 console控制臺(tái)實(shí)時(shí)監(jiān)測(cè)運(yùn)算過(guò)程
為了讓讀者更好的體驗(yàn)該小程序的運(yùn)行效果,同時(shí)針對(duì)小程序中存在的不足,也歡迎讀者提出您的寶貴意見(jiàn)。讀者可以使用微信掃一掃功能運(yùn)行計(jì)算器小程序。二維碼如圖3所示。
圖3 計(jì)算器小程序的二維碼
經(jīng)過(guò)一周的編程與不斷的測(cè)試調(diào)試,目前該項(xiàng)目已經(jīng)是2.1版本,所有微信用戶(hù)可以?huà)叽a使用,實(shí)現(xiàn)可以處理字符串表達(dá)式的,具有優(yōu)先級(jí)處理功能的計(jì)算器。不論是頁(yè)面的美觀度、用戶(hù)的體驗(yàn)度,還是功能的正確性、完善性與代碼的健壯性,都能滿(mǎn)足專(zhuān)業(yè)的要求。