C++11正则表达式+中缀表达式转后缀表达式+后缀表达式计算

C++11正则表达式+中缀表达式转后缀表达式+后缀表达式计算,第1张

上干货,关于使用C++11的regex正则匹配字符串的过程

#include
#include
#include
using namespace std;
int main()
{
	regex r1("\\d+");
	regex r2("\[+|-|*|/]");
	string s = "1+22+33+44-55+6+77-88+99+100*8+50/2+97*3";
	smatch result;
	auto iter_begin = s.cbegin();
	auto iter_end = s.cend();
	stack s1;
	stack s2;
	while (regex_search(iter_begin, iter_end, result, r1))
	{
		int num = atoi(result.str().c_str());
		s1.push(num);
		iter_begin = result[0].second;	//更新迭代器位置
	}
	iter_begin = s.cbegin();
	iter_end = s.cend();
	while (regex_search(iter_begin, iter_end, result, r2))
	{
		s2.push(result.str());
		iter_begin = result[0].second;	//更新迭代器位置
	}
	return 0;
}

写的比较繁琐,但是便于理解。

首先要写正则规则,这里先介绍r1规则。规则是自己定的,首先规则是一个字符串,第一个字符要用 \ 转义,后面就是要匹配的规则。这里我们第一行使用\d是匹配数字的意思,后面有个+号则是一个或多个的意思。程序用此规则做计算的流程是:扫描字符串,遇到了数字,就会继续扫描下一个,直到扫描到非数字,这样,字符串中的数字就会与所有的非数字分开。

如何把这些结果保留下来呢?我这里使用regex_search函数,这个函数被重载过多次,选择传入字符串的首尾指针(注意是const型,因此我们用cbegin而不用begin),匹配结果result,r1规则 四个参数。regex_search函数会从首指针开始扫描,扫描到数字后会继续扫描下一个,直到扫描到非数字,然后把已经扫描的结果(也就是匹配成功的结果)存入result,并且返回true。result是一个smatch对象,关于其具体的定义以及实现可另行查阅。再通过调用result的str()返回string类型,然后就能正常push进自己的容器里。随后要更新起始指针,使其指向匹配结果在字符串中的下一个索引。

最后介绍一下C++正则语法的书写:

如果匹配字符,用[]。比如r2规则匹配+-*/四种算数运算符号,中间用|隔开表示或的意思,再有需要用的规则不会写可以参考下面博主的文章。

下面贴一下完整中缀表达式计算的过程

中缀表达式转后缀表达式的算法原理可参考b站动画,直接搜中缀转后缀。

#include
#include
#include
#include
#include
using namespace std;

map t = {
	{"+",1},{"-",1},{"*",2},{"/",2}
};//这里是为了定义符号优先级

int main()
{
	regex r1("\\d+");
	regex r2("\[+|-|*|/]");
	string s = "16+2*30/4";
	smatch result;
	auto iter_begin = s.cbegin();
	auto iter_end = s.cend();
	queue q;//队列q用于存放后缀表达式
	stack s1;//临时存放计算符号
	stack calresult;//处理后缀表达式的计算结果用的栈

	//以下为中缀转后缀
	while (regex_search(iter_begin, iter_end, result, r1))
	{
		q.push(result.str());
		iter_begin = result[0].second;
		if (iter_begin != iter_end) {
			char s = *iter_begin;//由于在上两行出把指针给重新赋值了,所以这里指针会指向已经匹配到的字串的下一位地址,比如123+,指向+
			string st = "";
			st.append(1, s);//这里s转字符串,用的append方法,目的是为了能保持压栈,因为我们的栈初始化存放string类型的数据
			while (!s1.empty()) {
				if (t[s1.top()] >= t[st]) {
					q.push(s1.top());
					s1.pop();//记得压入队列后要把此符号删掉
				}
				else {
					break;
				}//这里核心意思是如果当前符的优先级小于栈顶符优先级,则正常压栈,否则将高优先级符号压入队列并且再继续判断当前符与栈顶符的优先级
			}
			s1.push(st);
		}
	}
	while (!s1.empty()) {
		q.push(s1.top());
		s1.pop();
	}//出来之后再看看符号栈是否还有符号,有就顺序入队列,最终队列形成我们需要的后缀表达式

	//以下计算后缀表达式
	//计算后缀表达式,表达式第一个元素开始入栈,一直入栈,但遇符号就把栈顶俩元素拿出来做计算,用下面的元素加减乘除上面的元素,计算结果入栈
	while (!q.empty()) {
		if (q.front() == "+" || q.front() == "-" || q.front() == "*" || q.front() == "/") {
			int j = calresult.top();
			calresult.pop();//取数后要删掉
			int i = calresult.top();
			calresult.pop();//取数后要删掉
			if (q.front() == "+") {
				calresult.push(i + j);
			}
			else if (q.front() == "-") {
				calresult.push(i - j);
			}
			else if (q.front() == "*") {
				calresult.push(i * j);
			}
			else {
				calresult.push(i / j);//int的除法有待优化,可以考虑把小数部分计算出来,那需要改动的地方比较多
			}
		}
		else {
			int cooper = atoi(q.front().c_str());
			calresult.push(cooper);
		}
		q.pop();//每次处理一个元素要在队列中将它删掉
	}
	cout << calresult.top() << endl;//剩下栈中的最后一个元素就是计算结果
	return 0;
}

常用正则表达式汇总—(数字匹配/字符匹配/特殊匹配)_0x8g1T9E的博客-CSDN博客_正则表达式匹配数字比较常用的几个正则表达式(匹配数字)评注:匹配中文还真是个头疼的事,有了这个表达式就好办了匹配双字节字符(包括汉字在内):[^\x00-\xff]评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)匹配空白行的正则表达式:\n\s*\r评注:可以用来删除空白行匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?https://blog.csdn.net/sirobot/article/details/89478951

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1295940.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-10
下一篇 2022-06-10

发表评论

登录后才能评论

评论列表(0条)

保存