程式在接受使用者輸入算式時,或者你有一個字元型算式,它可能不是標準的英文字元型算式,在轉化成可計算的算式之前,我們要把它標準化。方法是有很多,如:窮盡式逐項替換法、分離字串逐一替換法、正則表示式替換方法、自定義字典替換法、自定義“類”之一勞永逸法……還要避開一些暗含陷阱的方法。效果圖0:
工具/原料
as3.0
步驟/方法
為了方便,我們先定義一個變數,並給它一個值——中文字元型算式:
var formula:String="{[[[(20+3)*5]]]-10-2.5}/ 2.5×(1134-500÷4)=";
我們需要的效果是:
var result:String="(((((20+3)*5)))-10-2.5)/2.5*(1134--500/4)”;
實現的方法細述如下:
窮盡式逐項替換法。
窮盡可能出現的情況,再用正則表示式匹配一個或多個替換項。因為字元型中文算式可能出現的情況為數不多,可以很容易地列舉。
function replace(str:String ):String {
formula = str.replace(/[\[\{{[(]/g,"(")//統一為英文左括號
str = str.replace(/[\]\}}])]/g,")")//統一為英文右括號
str = str.replace(/×/g,"*");
str= str.replace(/÷/g,"/");
str= str.replace(/[== ]/g,"");//去掉空格和等號
str= str.replace(/./g,".");
str= str.replace(/0/g,0);
str= str.replace(/1/g,1);
str= str.replace(/2/g,2);
str= str.replace(/3/g,3);
str= str.replace(/4/g,4);
str= str.replace(/5/g,5);
str= str.replace(/6/g,6);
str= str.replace(/7/g,7);
str= formula.replace(/8/g,8);
formula= formula.replace(/9/g,9);
return str
}
測試一下:
trace(formula=replace(formula));
結果是符合要求的:
(((((20+3)*5)))-10-2.5)/2.5*(1134-500/4)
如果把替換與被替換的內容估成陣列,使用迴圈賦值,豈不可以大大簡化程式碼?我們試下:
varsymbol:Array=["+","-","*","/","(",")","(",")","(",")","(",")","(",")",".","0","1","2","3","4","5","6","7","8","9","","","",""];
var char:Array=["+","-","×","÷","(",")","[","]","[","]","{","}","{","}",".","0","1","2","3","4","5","6","7","8","9","=","="," ","",];
//...標準化算式...去中文字元、等號、空格...................
function replace(str:String ):String {
var k:uint=symbol.length;
for (var j:uint =0; j
str=str.replace(char[j],symbol[j]);
}
return str;
}
測試一下:
trace(formula=replace(formula));
可惜呀,重複的字元中後面的中文字元不能替換掉:
((([(20+3)*5))]-10-2.5)/2.5*(1134-500/4)
看到了吧,問題在這:“1134-500”,第二個“1”和第二個“0”都沒有被替換掉。但這個帶有陷阱的方法,仍叫人怦然心動!在它啟發下,我寫出了下面的方法。
分離字串逐一替換法。
仍舊利用上面的兩個陣列做為替換與被替換的內容。構建帶有引數、有返回值的函式如下:
//...標準化算式...去中文字元、等號、空格.....replace:替換..............
function replace(str:String ):String {
varstring:String="";
vark:uint=symbol.length;
varn:uint=str.length;
for(var t:uint =0; t
vars:String=str.charAt(t);
for(var j:uint =0; j
s=s.replace(char[j],symbol[j]);//…………注意這句……..
}
string+=s;
}
returnstring;
}
可能有人會疑惑不解:出現相同的中文字元,不是可以用正則表示式中的標誌“/g”來匹配一個或者多個替換項嗎?問題是:正則表示式的模式不支援變數!!下面這樣是行不通的:
str=str.replace(/char[j] /g,symbol[j]);
如果能行的話,我是不會使用分離字串這個方法的。
自定義字典替換法。
你有過“暴力破解”共享軟體的經歷嗎?如果有過,那你一定知道“字典工具”。下面我們模擬“字典工具”做一個格式化算式的函式。在思想上,就是把中文算式看作是一個有序的密碼,通過我們的編碼字典來解釋它,還原它的本來面目。有趣吧?
var formula:String="{[[[(20+3)*5]]]-10-2.5}/ 2.5×(1134-500÷4)=";
varsymbol:Array=["+","-","*","/","(",")","+","-","*","/","(",")","(",")","(",")","(",")","(",")",".","0","1","2","3","4","5","6","7","8","9",".","0","1","2","3","4","5","6","7","8","9","","","",""];//謎底
var char:Array=["+","-","×","÷","(",")","+","-","*","/","(",")","[","]","[","]","{","}","{","}",".","0","1","2","3","4","5","6","7","8","9",".","0","1","2","3","4","5","6","7","8","9","=","="," ",""];//謎面
var dic:Array=[];//字典
function makeDic() {//製作字典
vark:uint=symbol.length;
for(var t:uint =0; t
dic[char[t]]=symbol[t];//編碼
}
}
makeDic();//製作
//...標準化算式...去中文字元、等號、空格.....replace:替換..............
function replace(str:String ):String {
varstring:String="";
vark:uint=str.length;
for(var j:uint =0; j
string+=dic[str.charAt(j)];//使用字典
}
returnstring;
}
測試一下:
trace(formula=replace(formula));
結果多麼令人歡欣鼓舞:
(((((20+3)*5)))-10-2.5)/2.5*(1134-500/4)
自定義“類”之一勞永逸法。
上面三種都是成熟的程式碼,都可以封裝成類。以第三個辦法為例:
這個類:在Lir包中,類名:Formula;建構函式為空;靜態方法:replace,有一個引數,接受字元型中文算式。函式有返回值:英文字元型標準算式。
有了這個類,實在是太好了,應用起來大大地方便了。在時間軸上輸入下面的程式碼:
import Lir .Formula
var formula:String="{[[[(20+3)*5]]]-10-2.5}/ 2.5×(1134-500÷4)=";
trace(Lir.Formula.replace(formula)); //呼叫類中的方法
就這上面這一點程式碼?對,就這一點程式碼!快執行程式,看下輸出的結果:
(((((20+3)*5)))-10-2.5)/2.5*(1134-500/4)
我們又見到了這個早已熟悉的標準算式了!哈哈哈……我們都可以開心地笑了……
來自實踐的體會絕對原創的經驗
作者:張志晨
2012.5.6