qt 判断逻辑表达式

业务场景

用户需要设定规则,我们根据用户输入的数值判断是否符合规则。
示例一:
用户认为满足如下条件的属于合格品:

(width<62.15|height>9.278)&(area>5.86|width>6)

(数字我随便敲的)

现在来了一批样品,得到了属性width等的数值。要判断样品是否合规

拆解

这个问题本质上是判断这样的一串逻辑表达式

(63.2<62.15|553.14>37.278)&(1035.68>536.86|63.2>43)

不带括号

我们先从简单的入手:
没有括号的情况
表达式就剩下 < > | &运算符
其中< >优先级更高一些
仿照[LeetCode] Basic Calculator I II III 总结
给出如下解法:

#include<deque>

QString getNumStr(QString judgeValue,int i)
{
    
    
	//浮点数
	QString pattern("\\d+(\\.\\d+)");
	QRegExp rx(pattern);
	int pos = rx.indexIn(judgeValue, i);
	if (pos > -1)
	{
    
    
		QString value = rx.cap(0);
		QString temp = rx.cap(1);
		return value;
	}
	//整数
	pattern = "-?\\d+";
	rx.setPattern(pattern);
	pos = rx.indexIn(judgeValue, i);
	if (pos > -1)
	{
    
    
		QString value = rx.cap(1);
		return value;
	}
	return "";
}
bool cal(QString judgeValue)
{
    
    
	judgeValue.remove(QRegExp("\\s"));
	int i = 0;
	double temp, curNum = 1;
	QChar preSign; //之前的符号
	std::deque<double> numberStack;
	std::deque<QChar> signStack;
	while (i < judgeValue.size() + 1)
	{
    
    
		QChar cur = judgeValue.at(i);
		if (cur.isDigit())
		{
    
    
			QString value = getNumStr(judgeValue, i);
			if (!value.isEmpty())
			{
    
    
				i = i + value.size() - 1;
				curNum = value.toDouble();
			}
			i++;
			continue;
		}
		else //遇到符号了,判断之前的符号
		{
    
    
			switch (preSign.unicode())
			{
    
    
			case '>':
			{
    
    
				temp = numberStack.back();
				temp = temp > curNum;
				numberStack.pop_back();
				numberStack.push_back(temp);
				break;
			}
			case '<':
			{
    
    
				temp = numberStack.back();
				temp = temp < curNum;
				numberStack.pop_back();
				numberStack.push_back(temp);
				break;
			}
			case '&':
			{
    
    
				numberStack.push_back(curNum);
				signStack.push_back('&');
				break;
			}
			case '|':
			{
    
    
				numberStack.push_back(curNum);
				signStack.push_back('|');
				break;
			}
			case ' ':
				break;
			default:
				numberStack.push_back(curNum);
			}
			preSign = cur;
		}

		i++;
	}

	//

	if (!numberStack.empty())
	{
    
    
		double result = numberStack.front();
		numberStack.pop_front();
		while (!numberStack.empty())
		{
    
    
			double cur = numberStack.front();
			numberStack.pop_front();
			QChar sign = signStack.front();
			signStack.pop_front();
			if (sign == "|")
			{
    
    
				result = cur || result;
			}
			else
			{
    
    
				result = cur && result;
			}
		}
		return result;
	}
	else
	{
    
    
		return false;
	}

}

int main(int argc, char *argv[])
{
    
    
	cal(" 90.3< 62.15 | 36.12>9.278 & 69.214>5.86");
	return 0;
}

技巧总结:

  1. 计算表达式 63.2<62.15: 需要存储 第一个数字63.2,运算符,第二个数字。遍历字符串时,指针走到62.15,其实不好判断是第几个数字。所以这里的处理办法是:指针走到下一个运算符,即 63.2<62.15| 中的 ‘|’,第一个数字存储在栈里,第二个存储在当前数字 curNum 中,前运算符保存在preSign中。这是才计算表达式63.2<62.15
  2. 与leetcode题不同的是,加减法可以被转换成正负号,我这里不行,所以需要先把所有的 <>算出,表达式里只剩下 数字和 | &之后,从队列numberStack,signStack取出数字和符号,从左到右计算逻辑运算符

带括号

两者的区别在于,需要先把括号里面的内容算出来,并返回一个结果
思路
在这里插入图片描述
所以:

bool cal(QString judgeValue)
{
    
    
	judgeValue.remove(QRegExp("\\s"));
	int i = 0;
	double temp, curNum = 1;
	QChar preSign; //之前的符号
	std::deque<double> numberStack;
	std::deque<QChar> signStack;
	while (i < judgeValue.size() + 1)
	{
    
    
		QChar cur = judgeValue.at(i);
		if (cur.isDigit())
		{
    
    
			QString value = getNumStr(judgeValue, i);
			if (!value.isEmpty())
			{
    
    
				i = i + value.size() - 1;
				curNum = value.toDouble();
			}
			i++;
			continue;
		}
		else if(cur == '(')
		{
    
    
			int j = i, count = 0;
			for (; i < judgeValue.size(); i++) {
    
    
				if (judgeValue[i] == '(') count++;
				if (judgeValue[i] == ')') count--;
				if (count == 0) break;
			}
			curNum = cal(judgeValue.mid(j + 1, i - j - 1));
		}
		else //遇到逻辑符号了,判断之前的符号
		{
    
    
			switch (preSign.unicode())
			{
    
    
				case '>':
				{
    
    
					temp = numberStack.back();
					temp = temp > curNum;
					numberStack.pop_back();
					numberStack.push_back(temp);
					break;
				}
				case '<':
				{
    
    
					temp = numberStack.back();
					temp = temp < curNum;
					numberStack.pop_back();
					numberStack.push_back(temp);
					break;
				}
				case '&':
				{
    
    
					numberStack.push_back(curNum);
					signStack.push_back('&');
					break;
				}
				case '|':
				{
    
    
					numberStack.push_back(curNum);
					signStack.push_back('|');
					break;
				}
				case ' ':
					break;
				default:
					numberStack.push_back(curNum);
			}
			preSign = cur;
		}

		i++;
	}

	//

	if (!numberStack.empty())
	{
    
    
		double result = numberStack.front();
		numberStack.pop_front();
		while (!numberStack.empty())
		{
    
    
			double cur = numberStack.front();
			numberStack.pop_front();
			QChar sign = signStack.front();
			signStack.pop_front();
			if (sign == "|")
			{
    
    
				result = cur || result;
			}
			else
			{
    
    
				result = cur && result;
			}
		}
		return result;
	}
	else
	{
    
    
		return false;
	}

}

解法

总的解法就是:

  1. 客户输入(width > 100 & height > 300) | (area < 600)
  2. 获取属性值 {“width” : 321, “height” : 560 , “area”: 235}
  3. 利用字符串替换得到要计算的表达式: (321> 100 & 560 > 300) | (235< 600)
  4. 计算bool cal(QString judgeValue); 返回结果

搞定

猜你喜欢

转载自blog.csdn.net/fuyouzhiyi/article/details/127100709
今日推荐