关于实现字符串表达式求值

由于自身思维不够活跃,思考问题逻辑不够清晰,所以小弟的师傅给小弟我布置了个作业,字符串表达式求值,以此希望达到锻炼我思维逻辑能力的目的。
历时14天,完成作业,相关知识以及技术并不高深,目的在于锻炼逻辑思维能力。在此也想跟有相关需要的同学们分享下解题思路,有不足之处也希望大家不吝赐教,指点出来。谢谢。

解决该问题时首先要解决判断运算符优先级问题,后来了解到后缀表达式(即逆波兰表达式)后,决定先将表达式分解成逆波兰表达式 ,然后再根据每个运算符取出数字进行相应的运算。计算到最后即为表达式的值
涉及string字符串、动态数组vector、逆波兰表达式(网上由相应的解析,书上并没有出现),迭代器(主要起取出以及作转换范围使用)的相关知识。

低配版(仅支持0-9的正整数计算,可以计算的运算符包含+ - * / % ^ & |)
代码如下:

  1 //原型: double Exper(const char * expr);
  2 //使用: double retval = Expr("1*2+(10/4)-3^1234");
  3 #include<iostream>
  4 #include<string>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<cstdio>
  9 using namespace std;
 10 
 11 bool gettruefalse(char a) //判断当前符号是否为符号
 12 {
 13 if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \
 14 a == '^' || a == '|' || a == '&' || a == '(' || a == ')')
 15 return true;
 16 else
 17 return false;
 18 }
 19 
 20 int getpriority(char c)  //判断当前运算符的优先级
 21 {
 22 int temp;
 23 if (c == '(')
 24 temp = 6;
 25 else if (c == '*' || c == '/' || c == '%')
 26 temp = 5;
 27 else if (c == '+' || c == '-')
 28 temp = 4;
 29 else if (c == '&')
 30 temp = 3;
 31 else if (c == '^')
 32 temp = 1;
 33 else if (c == '|')
 34 temp = 1;
 35 else if (c == ')') //如果为')',则一直将符号取出放入新字符串,直到遇到'('(6)
 36 temp = 0;
 37 return temp;
 38 }
 39 
 40 string getnbl(string str)  //将原字符串转为逆波兰形式的字符串
 41 {
 42 string ok;//用于存放转换成后缀表达式的容器
 43 vector<char>flag;//用于存放转换时的符号容器
 44 
 45 while (str.length() != 0)//将旧字符串转换完成前,无限循环
 46 {
 47 for (int a = 0; a < str.length(); a++) //遍历字符串
 48 {
 49 if (gettruefalse(str[a])) //如果当前字符为符号
 50 {
 51 //如果符号容器为空,或者当前符号优先级大于符号容器优先级,或者符号容器最后一个符号为(,压入
 52 if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) || getpriority(*(flag.end() - 1)) == 6)
 53 {
 54 flag.push_back(str[a]);//将当前符号放入符号容器
 55 str.erase(str.begin(), str.begin() + 1); //截断旧字符串中的符号
 56 break;//跳出for循环,重新遍历
 57 }
 58 else if (getpriority(str[a]) == 0) //是)吗
 59 {
 60 str.erase(str.begin(), str.begin() + 1);//删掉旧字符串的),并将符号容器的符号移到新字符串,直到遇到(
 61 while (getpriority(*(flag.end() - 1)) != 6)//遇到(之前 无限弹出容器里的符号
 62 {
 63 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符
 64 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去
 65 }
 66 if ((getpriority(*(flag.end() - 1)) == 6))//将(去掉
 67 {
 68 flag.erase(flag.end() - 1);
 69 break;//跳到开头while循环处
 70 }
 71 }
 72 else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1))) //当前符号优先级小于或等于符号容器最后一个符号
 73 {
 74 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符
 75 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去
 76 break;
 77 }
 78 }
 79 else //如果当前字符不为符号(即为数字或小数点)
 80 {
 81 ok += str[a];//将该数字转入新的字符串
 82 str.erase(a, 1); //在旧字符串中删除该数字
 83 break;//跳出for循环,重新开始遍历
 84 }
 85 }
 86 }
 87 //旧字符串清空后,将临时存放点的字符串依次取出放入新字符中
 88 while (flag.size() != 0)
 89 {
 90 ok += *(flag.end() - 1);
 91 flag.erase(flag.end() - 1);
 92 }
 93 return ok;
 94 }
 95 
 96 int jisuan(int a, char b, int c) //根据符号取数字进行相应的计算
 97 {
 98 int num = 0;//计算结果
 99 if (b == '+')
100 num = a + c;
101 else if (b == '-')
102 num = a - c;
103 else if (b == '*')
104 num = a * c;
105 else if (b == '/')
106 num = a / c;
107 else if (b == '%')
108 num = a % c;
109 else if (b == '^')
110 num = a ^ c;
111 else if (b == '&')
112 num = a & c;
113 else if (b == '|')
114 num = a | c;
115 else if (b == 'M')
116 num = a && c;
117 else if (b == 'N')
118 num = a || c;
119 return num;
120 }
121 
122 int getcount(string nbl)  //将逆波兰形式的字符串进行转换为数字类型然后进行符号的运算
123 {
124 vector<int>nums;
125 int a = 0;
126 int answer; //存放结果
127 string zhuanhuan;
128 while (a < nbl.size())
129 {
130 if (gettruefalse(nbl[a]))//如果为符号
131 { //从数字容器中去除倒数第二的数作为A,最后一个数作为B,执行该符号的运算
132 answer = jisuan(*(nums.end() - 2), nbl[a], *(nums.end() - 1));
133 nums.erase(nums.end() - 2, nums.end());
134 nums.push_back(answer);
135 a++;//遍历下一个字符
136 }
137 else //数字时 压入数字容器
138 {
139 zhuanhuan += nbl[a];
140 answer = atof(zhuanhuan.c_str());
141 nums.push_back(answer);
142 zhuanhuan.clear();
143 a++;
144 }
145 }
146 return *(nums.end() - 1); //容器最后一位数即为结果
147 }
148 
149 int main()
150 {
151 char ch[100];
152 cout << "输入你要计算的字符串表达式(仅支持0-9的正整数运算):" << endl;
153 gets_s(ch);
154 cout << "字符串的原内容为:" << ch << endl;
155 
156 string str(ch);//用于进行转换操作的字符串
157 string nbl;//用于存放转换成后缀表达式的容器
158 nbl = getnbl(str);//调用函数 将字符串转为逆波兰字符串
159 cout << "转为逆波兰表达式后:" << nbl << endl;
160 int num = getcount(nbl);
161 cout << "字符串:" << ch << "的结果为:" << num << endl;
162 
163 system("pause");
164 fflush(stdin);
165 return 0;
166 }`
View Code

 

 

 

 

完全版(此时可以计算正负的整数(不支持小数点),运算符也包含+ - * / % & && ^ | ||):

  1 //原型: double Exper(const char * expr);
  2 //使用: double retval = Expr("1*2+(10/4)-3^1234");
  3 #include<iostream>
  4 #include<string>
  5 #include<vector>
  6 #include<cstdio>
  7 using namespace std;
  8 
  9 int gettruefalse(char a) //判断当前符号是否为运算符或数字
 10 {
 11 if (a == '1' || a == '2' || a == '3' || a == '4' || a == '5' || \
 12 a == '6' || a == '7' || a == '8' || a == '9' || a == '0')
 13 return 2;
 14 else if (a == '+' || a == '-' || a == '*' || a == '/' || a == '%' || \
 15 a == '^' || a == '|' || a == '&' || a == '(' || a == ')' || a == 'M' || a == 'N')
 16 return 1;
 17 else
 18 return 0;
 19 }
 20 
 21 int getpriority(char c) //优先级排列
 22 {
 23 int temp;
 24 if (c == '(')
 25 temp = 8;
 26 else if (c == '*' || c == '/' || c == '%')
 27 temp = 7;
 28 else if (c == '+' || c == '-')
 29 temp = 6;
 30 else if (c == '&')
 31 temp = 5;
 32 else if (c == '^')
 33 temp = 4;
 34 else if (c == '|')
 35 temp = 3;
 36 else if (c == 'M') //等同于&&
 37 temp = 2;
 38 else if (c == 'N') //等同于||
 39 temp = 1;
 40 else if (c == ')') //如果为')',则一直将符号取出放入新字符串,直到遇到'('(6)
 41 temp = 0;
 42 return temp;
 43 }
 44 
 45 void getvariant(string &str)
 46 {
 47 int a = 0;//用于遍历
 48 for (a = 0; a < str.size(); a++) //将原字符串中的-(符号)用相应的标识符替换
 49 {
 50 if ((a == 0) && (str[a] == '-'))
 51 {
 52 str[a] = '.';
 53 }
 54 else if ((str[a] == '-') && (gettruefalse(str[a - 1]) == 1) && (str[a - 1] != ')')) //找到-并确认当前是否为符号
 55 {
 56 str[a] = '.';
 57 }
 58 }
 59 for (a = 0; a < str.size(); a++) //将原字符串中的||、&&用相应的标识符替代
 60 {
 61 if (str[a] == '|' && str[a + 1] == '|')
 62 {
 63 str[a + 1] = 'N';
 64 str.erase(a, 1);
 65 }
 66 if (str[a] == '&' && str[a + 1] == '&')
 67 {
 68 str[a + 1] = 'M';
 69 str.erase(a, 1);
 70 }
 71 }
 72 }
 73 
 74 string getnbl(string str)
 75 {
 76 getvariant(str);//调用函数用标记符替换字符串中的||、&&、-(负号)
 77 string ok;//用于存放转换成后缀表达式的容器
 78 vector<char>flag;//用于存放转换时的符号容器
 79 int a = 0;//用于作为遍历字符串的下标
 80 int b = a;//!b作为开始遍历数字的起始点
 81 
 82 while (a <str.length())//遍历整个字符串
 83 {
 84 if ((gettruefalse(str[a])) == 1)//当前字符为符号
 85 {
 86 //符号容器为空或者当前符号优先级大于容器末尾符号优先级,或当前容器末尾为(,压入容器
 87 if (flag.size() == 0 || (getpriority(str[a]) > getpriority(*(flag.end() - 1))) \
 88 || *(flag.end() - 1) == '(')
 89 {
 90 flag.push_back(str[a]);
 91 a++;
 92 }
 93 else if (str[a] == ')') //如果为) 不压入,弹出容器符号 直到遇到(
 94 {
 95 while (*(flag.end() - 1) != '(')//当前符号不为(,则一直弹出容器符号
 96 {
 97 ok += *(flag.end() - 1);
 98 ok += ' '; //每个符号以空格作为间隔
 99 flag.erase(flag.end() - 1);
100 }
101 flag.erase(flag.end() - 1);//删掉容器中的(
102 a++;//跳过')'符号
103 }
104 else if (getpriority(str[a]) <= getpriority(*(flag.end() - 1)))//当前符号优先级小于或等于符号容器最后一个符号
105 {
106 ok += *(flag.end() - 1);//将符号容器的符号添加到新字符
107 ok += ' ';
108 flag.erase(flag.end() - 1);//将刚被添加到新字符的字符删去
109 }    
110 }
111 else //不为符号,则遍历字符串找到符号
112 {
113 b = a; //记录当前开始遍历的位置
114 while(a<str.size())
115 {
116 if ( (gettruefalse(str[a]) == 1)) //当当前字符为符号
117 {
118 ok.append(str.begin() + b, str.begin() + a);//将遍历的起始位置到发现符号的位置的所有字符拼接到新的字符串,并加上空格作为间隔
119 ok += ' ';
120 break; //跳出for循环 重新进行判断
121 }
122 else if ((a==(str.size()-1)) && (gettruefalse(str[a]) == 2)) //已经遍历到最后一个字符了 且最后一个字符为数字
123 {
124 a++;
125 ok.append(str.begin() + b, str.begin() + a);//将遍历的起始位置到发现符号的位置的所有字符拼接到新的字符串,并加上空格作为间隔
126 ok += ' ';
127 break; //跳出for循环 重新进行判断
128 }
129 a++;
130 }
131 }
132 }
133 while (flag.size() != 0) //遍历完原字符串后,将符号容器的符号全部弹出
134 {
135 ok += *(flag.end() - 1);
136 ok += ' '; //每个符号以空格作为间隔
137 flag.erase(flag.end() - 1);
138 }
139 return ok;
140 }
141 
142 int getanswer(int a, char b, int c)
143 {
144 int num = 0;//计算结果
145 if (b == '+') 
146 num = a + c;
147 else if (b == '-')
148 num = a - c;
149 else if (b == '*')
150 num = a * c;
151 else if (b == '/')
152 num = a / c;
153 else if (b == '%')
154 num = a % c;
155 else if (b == '^')
156 num = a ^ c;
157 else if (b == '&')
158 num = a & c;
159 else if (b == '|')
160 num = a | c;
161 else if (b == 'M')
162 num = a && c;
163 else if (b == 'N')
164 num = a || c;
165 return num;
166 
167 }
168 
169 int getcount(string nbl) //计算逆波兰表达式的
170 {
171 int num=0;//结果
172 string zhuanhuan;
173 vector<int> nums;//数字容器
174 int a = 0;//遍历字符串下标
175 int b = a;//记录开始遍历时的下标
176 while (a < nbl.size())
177 {
178 if (gettruefalse(nbl[a])==1) //当前为符号
179 {
180 if (((nbl[a] == '/') || (nbl[a] == '%')) && (*(nums.end() - 1) == 0)) //计算除法和求余时,如果被除数为0,报错
181 {
182 cout << "除数不能为0,程序退出" << endl;
183 system("pause");
184 exit(-1);
185 }
186 
187 num = getanswer(*(nums.end() - 2), nbl[a], *(nums.end() - 1));//弹出数字容器的2个数字 并根据符号去计算这2个数字
188 nums.erase(nums.end() - 2, nums.end());//计算后去掉这2个数字,并将结果重新放入容器中
189 nums.push_back(num);
190 a++;//遍历下一个字符
191 }
192 else if (nbl[a] == ' ')
193 {
194 a++;
195 }
196 else
197 {
198 b = a;//记录开始找空格的位置
199 while (a<nbl.size())
200 {
201 if (nbl[a] == ' ')//找到空格
202 {
203 if (nbl[b] == '.') //如果该数为负数(起始处为.)
204 {
205 nbl[b] = '-'; //将小数点转换为负号
206 }
207 zhuanhuan.append(nbl.begin() + b, nbl.begin() + a);
208 num = atof(zhuanhuan.c_str()); //将该字符串转换为数字 并压入数字容器中
209 zhuanhuan.clear();
210 nums.push_back(num);
211 break;
212 }
213 a++;
214 }
215 
216 }
217 }
218 num = *(nums.end() - 1);
219 return num;
220 }
221 
222 int main()
223 {
224 char ch[100];
225 cout << "输入你要计算的字符串表达式(仅支持整数运算):" << endl;
226 gets_s(ch);
227 string str(ch);//用于进行转换操作的字符串
228 int s = 0;
229 while (s < str.size())//检查用户输入表达式是否正确
230 {
231 if (gettruefalse(str[s]) == 0)
232 {
233 cout << "字符串表达式输入错误" << endl;
234 system("pause");
235 return 0;
236 }
237 s++;
238 }
239 string nbl;//用于存放转换成后缀表达式的容器
240 nbl = getnbl(str);//调用函数 将字符串转为逆波兰字符串
241 int num;//表达式结果
242 num = getcount(nbl);    
243 cout << "转为逆波兰表达式后:" << nbl << ",.(-)、M(&&)、N(|| )为标记符"<<endl;
244 cout << "字符串表达式:" << ch << "的结果为:" << num << endl;
245 cout << "结果为:" << num << endl;
246 system("pause");
247 fflush(stdin);
248 return 0;
249 }
View Code

 

运行结果:

 

posted @ 2019-07-03 23:48  __阿阿阿怪  阅读(1928)  评论(0编辑  收藏  举报