MFC计算器主要分为以下三个部分:
1、去括号
2、字符串规范化
3、计算结果
一、去括号
首先建立一个结构体作为括号匹配的栈
typedef struct tagINDEXSTACK /*括号下标*/
{
int data[StackSize]; /*存取字符串中'('与')'的下标*/
int top;
}IndexStack;
然后利用栈原理进行括号匹配
二、字符串规范化
首先除去所有无效字符,然后判断第一个字符是否为'-',如果是,则在字符串头上加上'0'
然后处理连续的负号
然后处理连续的运算符(第一个+ - * /,第二个是 -)
然后取出字符串中的运算数与运算符,分别保存到下面结构体的两个数组
typedef struct tagEXPRESS
{
double numget[20];
char charget[10];
int lengthget;
CString str_16;
}EXPRESS;
三、计算结果
根据运算数与运算符数组,按照运算规则计算出结果
下面是相关函数
/***********************************************************************************************************************/
/*************************************堆栈处理函数**********************************************************************/
void CCalculatorDlg::IndexInitial(IndexStack *S) /*置栈空*/
{
S->top = -1;
}
int CCalculatorDlg::IndexIsEmpty(IndexStack *S) /*判断栈是否为空*/
{
return S->top == -1;
}
int CCalculatorDlg::IndexIsFull(IndexStack *S) /*判断栈是否为满*/
{
return S->top == StackSize - 1;
}
void CCalculatorDlg::IndexPush(IndexStack *S, int x) /*进栈*/
{
if (IndexIsFull(S))
{
exit(1);
}
S->data[++S->top] = x;
}
int CCalculatorDlg::IndexPop(IndexStack *S) /*出栈*/
{
if (IndexIsEmpty(S))
{
return -1;
}
return S->data[S->top--];
}
int CCalculatorDlg::IndexTop(IndexStack *S) /*取栈顶元素*/
{
if (IndexIsEmpty(S))
{
exit(1);
}
return S->data[S->top];
}
/*************************************************堆栈处理函数结束******************************************************/
/***********************************************************************************************************************/
/**********************************************字符串处理函数***********************************************************/
/***********************************************************************************************************************/
double CCalculatorDlg::GetaStr(CString str) /*如果一个字符串是一个纯数字,则返回对应的double型数字*/
{
int i = 0;
double rate = 10.0, itemp = 0.0;
for (i = 0; i < str.GetLength(); i++)
{
if (isdigit(str.GetAt(i))) /*判断字符str.GetAt(i)是否是0-9*/
{
if (rate == 10.0) /*整数部分*/
itemp = itemp * rate + (str.GetAt(i) - '0'); /*获得整数*/
else /*小数部分*/
{
itemp = itemp + rate * (str.GetAt(i) - '0'); /*获得小数*/
rate /= 10;
}
}
else
if (str.GetAt(i) == '.') /*如果str.GetAt(i)是小数点*/
rate = 0.1;
}
return itemp;
}
int CCalculatorDlg::DelChar(char *data, char ch, int len) /*删除字符串中的所有特定字符,返回新字符串的长度*/
{
int i = 0, k = 0;
for (i = 0; i < len; i++)
{
if (data[i] != ch)
data[k++] = data[i];
}
data[k] = '\0';
return k;
}
int CCalculatorDlg::DelaChar(char *data, int index, int len) /*删除字符串中的某个位置字符,返回新字符串的长度*/
{
int i = 0, k = 0;
if (index >= len)exit(1);
for (i = index; i < len; i++)
{
data[i] = data[i + 1];
}
data[len - 1] = '\0';
return len - 1;
}
void CCalculatorDlg::GetStr(char *str, EXPRESS *fp)
{
int i = 0, j = 0, len = 0, k = 0, z = 0;
int indexnum[20], flag = 0;/*用于处理连续的运算符*/
char specstr[512] = "";
int t = 1;
double rate = 10.0, itemp = 0.0;
for (i = 0; i < 20; i++)
fp->numget[i] = 1000000.0; /*对数组numget[20]初始化*/
for (i = 0; i < 10; i++)
fp->charget[i] = ' '; /*对数组charget[10]初始化*/
for (i = 0; i < 20; i++)
indexnum[i] = 0; /*对数组numget[20]初始化*/
printf("原始数据%s\n", str);
for (i = 0; i < strlen(str); i++)
{
if (isdigit(str[i]) || str[i] == '.' || str[i] == '+' || str[i] == '-' ||
str[i] == '*' || str[i] == '/')
specstr[len++] = str[i];
}
printf("除去无效字符%s\n", specstr);
if (specstr[0] == '-')
{
len++;
for (k = len - 1; k > 0; k--)
specstr[k] = specstr[k - 1];
specstr[0] = '0';
}
printf("开始有负号%s\n", specstr);
len = DelChar(specstr, ' ', len); /*除去多余的空格*/
printf("除去多余的空格%s\n", specstr);
k = 0;
for (i = 1; i < len; i++) /*如果有连续的‘-’*/
{
if (specstr[i] == '-')
{
j = i;
t = isdigit(specstr[i - 1]) || specstr[i - 1] == '.';
while (specstr[j] == '-')
{
k++;
specstr[j++] = ' ';
}
i = j;
if (k % 2) specstr[j - 1] = '-';
else if (t) specstr[j - 1] = '+';
k = 0;
}
}
printf("除去连续的负号%s\n", specstr);
len = DelChar(specstr, ' ', len); /*除去多余的空格*/
printf("除去多余的空格%s\n", specstr);
k = 0;
for (i = 0; i < len - 1; i++)
{
if (specstr[i] == '*' || specstr[i] == '/' || specstr[i] == '+' || specstr[i] == '-')
{
flag++; /*运算符计数*/
if (specstr[i + 1] == '-')
{
indexnum[k++] = flag; /*记录连续运算符在所有运算符中的位置*/
len = DelaChar(specstr, i + 1, len);
}
}
}
printf("处理连续的运算符%s\n连续运算符在所有运算符中的位置", specstr);
for (i = 0; i < k; i++)
printf("%d ", indexnum[i]);
printf("\n");
for (i = 0; i < len; i++)
{
if (isdigit(specstr[i])) /*如果字符串specstr[i]的内容是整数*/
{
if (rate == 10.0) /*整数部分*/
itemp = itemp * rate + (specstr[i] - '0'); /*获得整数*/
else /*小数部分*/
{
itemp = itemp + rate * (specstr[i] - '0'); /*获得小数*/
rate /= 10;
}
}
else
switch (specstr[i])
{
case '.': /*如果str.GetAt(i)是小数点*/
rate = 0.1;
break;
case '+': /*如果str.GetAt(i)是加号*/
fp->numget[z++] = itemp;
itemp = 0; /*把itemp的值放入双精度数组numget中,并把itemp的值改为0*/
fp->charget[z++] = '+';
rate = 10.0; /*把10赋给rate,确保读取下个数字时,先计算整数部分*/
break;
case '-':
fp->numget[z++] = itemp;
itemp = 0;
fp->charget[z++] = '-';
rate = 10.0;
break;
case '*':
fp->numget[z++] = itemp;
itemp = 0;
fp->charget[z++] = '*';
rate = 10.0;
break;
case '/':
fp->numget[z++] = itemp;
itemp = 0;
fp->charget[z++] = '/';
rate = 10.0;
break;
}
}
fp->numget[z] = itemp; /*把最后一个整数itemp的值放入双精度数组a中*/
fp->lengthget = z + 1;
#if 0
for (i = 0; i < 20; i++)
{
if (indexnum[i] != 100)
{
fp->numget[indexnum[i] + 1] *= -1.0;
printf("%lf\n", fp->numget[indexnum[i] + 1]);
}
}
#endif
k = 0;
for (i = 0; i < fp->lengthget; i++)
{
if (fp->charget[i] == '+' || fp->charget[i] == '-' || fp->charget[i] == '*' || fp->charget[i] == '/')
{
k++;
for (j = 0; j < 20; j++)
if (k == indexnum[j])
fp->numget[i + 1] *= -1.0;
}
}
printf("长度为 %d\n", fp->lengthget);
for (i = 0; i < fp->lengthget; i++)
{
printf("%lf ", fp->numget[i]);
}
printf("\n");
for (i = 0; i < fp->lengthget; i++)
{
printf("%c ", fp->charget[i]);
}
printf("\n");
}
double CCalculatorDlg::GetResult(EXPRESS *fp)
{
int i = 0, x = 0, y = 1, t = 0, z = 1;
for (i = 0; i <= fp->lengthget; i++) /*把所有除法运算都改为乘法计算*/
{
if (fp->charget[i] == '/') /*当循环遇到除号时*/
{
fp->numget[i + 1] = 1 / fp->numget[i + 1]; /*把numget[i+1]的值改为1/numget[i+1]*/
fp->charget[i] = '*'; /*把charget[i]的值改为乘号*/
}
}
for (i = 0; i <= fp->lengthget; i++) /*对所有乘法进行计算*/
{
if (fp->charget[i] == '*') /*当循环遇到乘号时*/
{
if (i - t == 2)
{
fp->numget[t - z] = fp->numget[t - z] * fp->numget[i + 1]; /*进行乘法运算,把结果保存在前面的数组元素中*/
z += 2; /*这里引进变量z,可以解决很多数连续相乘的问题,比如 2*2*2*2*2*2 */
}
else
fp->numget[i - 1] = fp->numget[i - 1] * fp->numget[i + 1]; /*碰到乘号后把乘号前后2个数字相乘,结果保存在前面的数组元素*/
fp->numget[i + 1] = 1000000.0; /*对乘号后面的数字初始化为0.0*/
fp->charget[i] = ' '; /*对乘号初始化为空格*/
t = i;
}
}
for (i = 0; i < fp->lengthget; i++)
{
if (fp->numget[i] != 1000000.0)
{
fp->numget[x] = fp->numget[i];
x += 2;
}
if (fp->charget[i] != ' ')
{
fp->charget[y] = fp->charget[i];
y += 2;
}
}
for (i = 0; i <= y - 2; i++) /*进行最后的加减法运算,这里i的上限小于等于y-2,可以保证不进行多余的运算*/
{
if (fp->charget[i] == '+')
fp->numget[0] = fp->numget[0] + fp->numget[i + 1];
if (fp->charget[i] == '-')
fp->numget[0] = fp->numget[0] - fp->numget[i + 1];
}
printf("处理结果%lf\n\n", fp->numget[0]);
return fp->numget[0];
}
double CCalculatorDlg::BracketMatch(char *expr) /*括号匹配*/
{
IndexStack S; /*括号下标*/
char allstr[512] = ""; /*处理掉括号以后的字符串*/
EXPRESS alldate; /*处理掉括号以后的用于匹配运算符的结构体*/
int i, j, length = strlen(expr), barcketcount = 0;
double barckettemp[32] = { 0 }; /*存取每个括号内的计算结果*/
IndexInitial(&S);
for (i = 1; i <= length; i++) /*处理所有括号*/
{
if (expr[i - 1] == '(')
{
IndexPush(&S, i);
}
else if (expr[i - 1] == ')')
{
j = IndexPop(&S);
if (j == -1)
{
exit(1);
}
else
{
EXPRESS dataget; /*计算两括号之间的字符串的值*/
char Bracketstr[512] = ""; /*存取两括号之间的字符串*/
int k = 0;
for (k = j; k <= i - 2; k++)
{
if (expr[k] == '_')
{
char strtemp[16] = "";
sprintf(strtemp, "%.1f", barckettemp[expr[k++ + 1] - '0']);
strcat(Bracketstr, strtemp);
}
else
{
char temp[16] = "";
sprintf(temp, "%c", expr[k]);
strcat(Bracketstr, temp);
strcpy(temp, "");
}
}
GetStr(Bracketstr, &dataget);
expr[j - 1] = '_';
expr[j] = barcketcount + '0';
barckettemp[barcketcount++] = GetResult(&dataget);
for (k = j + 1; k <= i - 1; k++)
expr[k] = ' ';
}
}
}
for (i = 0; i < length; i++)
{
if (expr[i] == '_')
{
char strtemp[16] = "";
sprintf(strtemp, "%.1f", barckettemp[expr[i++ + 1] - '0']);
strcat(allstr, strtemp);
}
else
{
char temp[16] = "";
sprintf(temp, "%c", expr[i]);
strcat(allstr, temp);
strcpy(temp, "");
}
}
GetStr(allstr, &alldate);
return(GetResult(&alldate));
}
void CCalculatorDlg::int_16(int n) /*十进制转化为十六进制*/
{
CString str1;
int x;
if ((n / 16) != 0) /*如果n大于等于16*/
int_16(n / 16); /*把n除以16,进行递归调用*/
x = n % 16; /*把n除以16的余数赋给x*/
if (x >= 0 && x <= 9) /*如果x在0到9之间*/
{
str1.Format("%d", x);
str_16 += str1;
}
else
str_16 += char(x + 55); /*把x的值加55(利用ASCII码)再转化为字符型加在str_16上*/
}
/*************************************************字符串处理函数结束****************************************************/
/***********************************************************************************************************************/