程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 用於計算四則混合運算表達式的遞歸函數第二版

用於計算四則混合運算表達式的遞歸函數第二版

編輯:關於C++

用於計算四則混合運算表達式的遞歸函數第二版

更新於2007-08-28 by billow3(QQ:41965573)

注:本文在發表時稍作了排版,如果有因排版引起的代碼工作不正常請來信告知我們

#include <math.h>
#pragma warn -8060 // 屏蔽編譯時的 Possibly incorrect assignment 警告
AnsiString __fastcall Calc(String sExp)
{
// 計算不帶變量的四則混合運算表達式(支持取整int和圓整round函數,支持負操作數)
// 正數不許帶正號
int posL, pos, posR, posM; // pos->當前考慮的運算符的位置
// posL->當前考慮的運算符之前最近的運算符的位置
// posR->當前考慮的運算符之後最近的運算符的位置
// posM->圓整函數中逗號的位置
String sTmp, sL, sR;
// sL->當前考慮的運算符的左操作數字符串,sR->當前考慮的運算符的右操作數字符串
bool IsMinus; // IsMinus->當前*/序列的符號
sExp = sExp.LowerCase();
if(sExp.AnsiPos("error"))
return(sExp);
while(pos = sExp.AnsiPos(" "))
sExp = sExp.Delete(pos, 1); // 去除表達式中的空格
if(sExp.IsEmpty())
return("0");
while((pos = sExp.AnsiPos("[")) > 0 || (pos = sExp.AnsiPos("{")) > 0) // 統一左括號為(
sExp = sExp.SubString(1, pos - 1) + "("
+ sExp.SubString(pos + 1, sExp.Length());
while((pos = sExp.AnsiPos("]")) > 0 || (pos = sExp.AnsiPos("}")) > 0) // 統一右括號為)
sExp = sExp.SubString(1, pos - 1) + ")"
+ sExp.SubString(pos + 1, sExp.Length());
// 以下處理round圓整函數
while(pos = sExp.AnsiPos("round("))
{
posL = pos + 5;
while(posM = sExp.SubString(posL + 1, sExp.Length()).AnsiPos("round("))
posL = posL + posM + 5; // 最後一個round之後的位置
for(posM = posL + 2; !sExp.IsDelimiter(",", posM)
&& posM <= sExp.Length(); posM++); // round後第一個, 的位置
if(posM == 0) return("error:round沒有配對的逗號, 公式錯!");
for(posR = posM + 2; !sExp.IsDelimiter(")", posR)
&& posR <= sExp.Length(); posR++); // 逗號後第一個)的位置
// posR不從posM + 1而從posM + 2開始搜索,是為了應對操作數為負的情況
sExp = sExp.SubString(1, posL - 6)
+ floor(Calc(sExp.SubString(posL + 1,
posM - posL - 1)).ToDouble() * pow(10,
sExp.SubString(posM + 1, posR - posM - 1).ToDouble())
+ 0.5) / pow(10, sExp.SubString(posM + 1,
posR - posM - 1).ToDouble())
+ sExp.SubString(posR + 1, sExp.Length());
}
// 處理括號:遞歸計算括號中的表達式,最後消去括號
while(posL = sExp.LastDelimiter("(")) // 最裡層(
{
sTmp = sExp.SubString(posL + 1, sExp.Length());
posR = sTmp.AnsiPos(")"); // 最裡層)
if(posR == 0)
return("error:沒有配對的), 公式錯!");
sExp = sExp.SubString(1, posL - 1)
+ Calc(sTmp.SubString(1, posR - 1))
+ sTmp.SubString(posR + 1, sTmp.Length());
}
// 以下處理int取整函數
while(pos = sExp.AnsiPos("int"))
{
posL = pos + 2;
for(posR = posL + 2; !sExp.IsDelimiter("+-*/", posR)
&& posR <= sExp.Length(); posR++); // 其後第一個+-*/
// posR不從posL + 1而從posL + 2開始搜索,是為了應對操作數為負的情況
sExp = sExp.SubString(1, pos - 1)
+ floor(sExp.SubString(posL + 1, posR - posL - 1).ToDouble())
+ sExp.SubString(posR, sExp.Length());
// 本文轉自 C++Builder研究 - http://www.ccrun.com/article.asp?i=636&d=x5fncl
}
// 以下處理不帶括號表達式中的*/序列
IsMinus = false; // IsMinus->當前*/序列的符號
while(sExp.LastDelimiter("*/")) // 存在*或/
{
for(pos = 1;!sExp.IsDelimiter("*/", pos)
&& pos <= sExp.Length(); pos++); // 第一個*或/
if(pos == 1 || pos == sExp.Length())
return("error:首或尾字符是*/運算符, 公式錯!");
// posL->第一個*/之前的第一個+-
posL = sExp.SubString(1, pos - 1).LastDelimiter("+-");
Minus0:
for(posR = pos + 1;!sExp.IsDelimiter("+-*/", posR)
&& posR <= sExp.Length(); posR++);
// posR->第一個*/之後的第一個+-*/運算符
if(posR == (pos + 1) && sExp.IsDelimiter("*/", posR))
return("error:*/運算符相鄰, 公式錯!");
if(posR == sExp.Length())
return("error:尾字符是 + - */運算符, 公式錯!");
if(sExp.SubString(pos, 2) == "*-"
|| sExp.SubString(pos, 2) == "/-") // 乘數或除數為負
{
sExp.Delete(pos + 1, 1);
IsMinus = !IsMinus;
goto Minus0;
}
sL = sExp.SubString(posL + 1, pos - posL - 1);
sR = sExp.SubString(pos + 1, posR - pos - 1);
if(sExp.IsDelimiter("/", pos)&&sR == "0")
return("error:除數為零,無意義!");
sExp = (posL == 0? String(""):
sExp.SubString(1, posL)) + (sExp.IsDelimiter("*", pos)?
(sL.ToDouble()*sR.ToDouble()):
(sL.ToDouble()/sR.ToDouble()))
+ sExp.SubString(posR, sExp.Length());
}
if(IsMinus)
sExp = String("-") + sExp;
// 經過上面的系列處理,sExp中的運算符號只剩下+和-了
// 以下處理不帶括號表達式中的+-序列
IsMinus = false; // 加數或減數的符號
while(sExp.LastDelimiter("+-")) // 存在+或-
{
for(pos = 2; !sExp.IsDelimiter("+-", pos)
&& pos <= sExp.Length(); pos++); // 第一個+或-
// pos不從1而從2開始搜索,是為了應對首操作數為負的情況
if(pos == sExp.Length())
return("error:尾字符是+-運算符,公式錯!");
if(pos > sExp.Length())
return(sExp); // sExp是一個簡單的負數,不必計算
Minus1:
for(posR = pos + 1; !sExp.IsDelimiter("+-", posR)
&& posR <= sExp.Length(); posR++);
if(posR == sExp.Length())
return("error:尾字符是+-運算符,公式錯!");
if(sExp.SubString(pos, 2) == "+-"
|| sExp.SubString(pos, 2) == "--") // 加數或減數為負
{
sExp.Delete(pos + 1, 1);
IsMinus = !IsMinus;
goto Minus1;
}
// 此處跳轉在正常情況下最多只會執行一次
sL = sExp.SubString(1, pos - 1);
sR = sExp.SubString(pos + 1, posR - pos - 1);
sExp = String(sExp.IsDelimiter("+", pos)?
(sL.ToDouble() + sR.ToDouble() * (IsMinus? - 1:1)):
(sL.ToDouble() - sR.ToDouble() * (IsMinus? - 1:1)))
+ sExp.SubString(posR, sExp.Length());
}
return(sExp);
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved