就不用帖全部代码了把,核心代码都在了
CCALC_NBL::CCALC_NBL(void)
{
}
CCALC_NBL::~CCALC_NBL(void)
{
}
//计算四则混合运算
//str 运算式 len:字符串长度 result:结果
bool CCALC_NBL::GetCalcResult(const char * str, int Len, double * result)
{
char calc_str[STRMAX] = { 0 };
if (InitStr(str, Len, calc_str))
return Calc(calc_str, Len, result);
return false;
}
//初始化字符串 合法性检测去空格
bool CCALC_NBL::InitStr(const char * str, int Len, char * result)
{
int index_str = 0, index_res = 0;
//Stack<char> eax;
for (; index_str < Len; index_str++)
{
char temp = str[index_str];
if (temp <= '9' && temp >= '0' || temp >= '(' && temp <= '+' || temp >= '-' && temp <= '/')//判断是否是合法字符串
result[index_res++] = temp;
else if (temp == 0)//判断是否结束
break;
else if (temp != ' ')//如果是空格跳过不是空格报错
return false;
}
result[index_res] = 0;
return true;
}
//根据后辍表达式计算结果
bool CCALC_NBL::Calc(const char * str, int Len, double * result)
{
char str_calc[STRMAX] = { 0 };
char str_t[STRMAX] = { 0 };
Stack<double> eax;
int index = 0;
//将中辍表达式转换成后辍表达式
if (InitCalcStr(str, Len, str_calc, ' '))
{
//遍历后辍表达式
while (str_calc[index] && index < Len)
{
//获取一个元素
int step = GetOne_calc(str_calc + index, Len - index, str_t, ' ');
if (step == 0)
return false;
index += step + 1;
//如果是数字
if (GetType(str_t[0]) == NUMBER)
{
double n;
//转成double 入栈 也可以自己写数组算法,支持大数
if (StrToDouble(str_t, step, &n))
if (!eax.IsFull())
eax.PUSH(n);
else
return false;
else
return false;
}
else
{
double n1, n2, n3 = 0.0;
//不是数字要栈最上面两个元素参与运算
if (!eax.IsEmpty())
n2 = eax.POP();
else
return false;
if (!eax.IsEmpty())
n1 = eax.POP();
else
return false;
//根据元素 做运算
switch (str_t[0])
{
case '+':
n3 = n1 + n2;
break;
case '-':
n3 = n1 - n2;
break;
case '*':
n3 = n1 * n2;
break;
case '/':
n3 = n1 / n2;
break;
default:
return false;
break;
}
//结果入栈
if (!eax.IsFull())
eax.PUSH(n3);
else
return false;
}
}
//返回结果
if (!eax.IsEmpty())
*result = eax.POP();
else
*result = 0.0;
return true;
}
return false;
}
//123 + 4 转成 123 4 +之后调用 同GetOne
int CCALC_NBL::GetOne_calc(const char * str, int Len, char * result, char fenge)
{
//后搓表达式用分隔符分开,很好获取
int index;
for (index = 0; str[index] != fenge && index < Len; index++)
result[index] = str[index];
result[index] = 0;
return index;
}
//把中辍表达式转成后辍表达式
bool CCALC_NBL::InitCalcStr(const char * str, int Len, char * result, char fenge)
{
int index = 0, index2 = 0;
char res[STRMAX] = { 0 };
Stack<char> eax;//创建栈
while (str[index] && index < Len)//遍历整个字符串
{
//获取一个元素
int step = GetOne(str + index, Len - index, res);
if (step == 0)
return false;//获取失败就返回假
index += step;//下标更新
int type = GetType(res[0]);//获取当前元素的类型
if (type == NUMBER)//如果是个数字就直接作为后辍表达式的一部分
{
int i;
for (i = 0; i < step; i++)
result[index2 + i] = res[i];
index2 += i;
//应为会有连续两个数字所以需要用分隔符分开
result[index2++] = fenge;
}
else
{
if (eax.IsEmpty())//如果当前栈为空
{
if (res[0] == ')')//并且直接出现 ) 说明不合法
return false;
else
eax.PUSH(res[0]);//入栈
}
else//栈不为空
{
if (res[0] == ')')//是 )
{
char topch;
//依次出栈直到遇到 ( 或者栈为空
while (!eax.IsEmpty() && (topch = eax.POP()) != '(')
{
result[index2++] = topch;
result[index2++] = fenge;
}
//如果没有 ( 说明不合法
if (topch != '(')
return false;
}
else//不是 )
{
//如果栈顶元素不是括号 并且 当前元素不是 (
if (GetType(eax.GetTop()) != KUOHAO && res[0] != '(')
{
//那就要判断当前元素和栈顶元素的优先级,如果当前元素的优先级小于栈顶元素的优先级,就要先做出栈操作。
if (GetType(res[0]) >= GetType(eax.GetTop()))
//依次出栈作为后辍表达式的一部分,直到站为空或者栈顶元素的优先级大于栈顶元素的优先级。
while (!eax.IsEmpty() && GetType(eax.GetTop()) <= GetType(res[0]))
{
result[index2++] = eax.POP();
result[index2++] = fenge;
}
}
//如果是(直接入栈 不是(做完以上操作之后也要入栈
eax.PUSH(res[0]);
}
}
}
}
//最后依次出栈作为后辍表达式的一部分
while (!eax.IsEmpty())
{
result[index2++] = eax.POP();
result[index2++] = fenge;
}
result[index2] = 0;
return true;
}
//123 + 4 ,result 第一次是123 第二次是 + 第三次是4 返回result长度
int CCALC_NBL::GetOne(const char * str, int Len, char * result)
{
int index = 0;
do
{
result[index] = str[index];
index++;
if ((GetType(str[0]) == ADDSUB || GetType(str[0]) == MULDIV) &&
(GetType(str[index]) == ADDSUB || GetType(str[index]) == MULDIV
|| GetType(str[index]) == KUOHAO))
return false;
} while (GetType(str[index]) == GetType(str[0]) && GetType(str[0]) == NUMBER && index < Len);
//首先 除了数字要读多个字符外其他都只要读一次。每一次读取到的字符都是数字,当然读完整个表达式也就结束了。其次+-*/之后只能是数字
result[index] = 0;
return index;
}
//返回类型 主要为了 +- */ (可以判断优先级
int CCALC_NBL::GetType(char ch)
{
if (ch == '(' || ch == ')')
return KUOHAO;
if (ch == '*' || ch == '/')
return MULDIV;
if (ch == '+' || ch == '-')
return ADDSUB;
if (ch == 0)
return ZERO;
return NUMBER;
}
//string转double
bool CCALC_NBL::StrToDouble(const char * str, int Len, double * res)
{
int index_d, index;
for (index_d = 0; index_d < Len; index_d++)
if (str[index_d] == '.')
break;
for (index = index_d + 1; index < Len; index++)
if (str[index] == '.')
return false;
double result = 0.0;
double p = 0.1;
for (index = 0; index < index_d; index++)
result = result * 10 + (double)(str[index] - '0');
for (index = index_d + 1; index < Len; index++)
{
result = result + (double)(str[index] - '0') * p;
p /= 10.0;
}
*res = result;
return true;
}
//Unicode转ansi
char* CCALC_NBL::UnicodeToAnsi(const wchar_t* szStr)
{
int nLen = WideCharToMultiByte(CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL);
if (nLen == 0)
return NULL;
char * pResult = new char[nLen];
WideCharToMultiByte(CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL);
return pResult;
}