数学表达式求值器出错
本文关键字:出错 表达式 | 更新日期: 2023-09-27 18:03:21
大家好
我已经开始通过使用Dijkstra两堆栈算法制作这个数学表达式评估器,我认为我已经仔细应用了所有规则,但问题是它可以正确评估一些表达式和一些错误:/
//I made it in a Console project
static void Main(string[] args)
{
string expression = "2*3+232+34*45/3-4*45+3";
//remove all whitespaces
expression = expression.Trim();
//two stacks needed
var values = new Stack<double>();
var operators = new Stack<char>();
Dictionary<char, OperatorInfo> operatorList = new Dictionary<char, OperatorInfo>
{
{'+',new OperatorInfo('+',"Add",2,OperatorFixity.Left)},
{'-',new OperatorInfo('-',"Minus",2,OperatorFixity.Left)},
{'/',new OperatorInfo('/',"Divide",3,OperatorFixity.Left)},
{'*',new OperatorInfo('*',"Multiply",3,OperatorFixity.Left)},
{'^',new OperatorInfo('^',"Caret",4,OperatorFixity.Right)}
};
for (int i = 0; i < expression.Length; i++)
{
if (expression[i].Equals('('))
continue;//ignore it
else if (IsNumber(expression[i].ToString()))//if its a number
{
//extract number
string[] getNumberNCount =
getNumberAndCount(expression.Substring(i)).Split(',');
double val = double.Parse(getNumberNCount[0]);
int count = int.Parse(getNumberNCount[1]);
values.Push(val);
i += count;
}
else if (IsOperator(expression[i]))
{
//Maintain precedence on stack
if (operators.Count > 0)
{
CheckPrecedence(expression[i], ref values, ref operators, operatorList);
}
else
operators.Push(expression[i]);//runs first time only
}
}
//now most precedence is solved
while (operators.Count != 0)
{
var LastOperand = values.Pop();
var PrevOperand = values.Pop();
var lastOperator = operators.Pop();
values.Push(calculateExpression(lastOperator, LastOperand, PrevOperand));
}
Console.WriteLine("Input Expression is: " + expression);
Console.WriteLine("Result is: " + values.Pop());
Console.ReadLine();
}
//it checks for precedence of operators before push
//that's the basic logic for calculation
private static void CheckPrecedence(char currentOp, ref Stack<double> values, ref Stack<char> operators, Dictionary<char, OperatorInfo> operatorList)
{
char lastStackOp = operators.Peek();
//if same precedence of both Op are same
//OR lastOp > than CurrentOp
if ((operatorList[lastStackOp].Precedence == operatorList[currentOp].Precedence) ||
(operatorList[lastStackOp].Precedence > operatorList[currentOp].Precedence))
{
var TopMostOperand = values.Pop();
var PrevOperand = values.Pop();
var TopMostOperator = operators.Pop();
values.Push(calculateExpression(TopMostOperator, TopMostOperand, PrevOperand));
operators.Push(currentOp);
}
else
{
operators.Push(currentOp);
}
}
//extracts out number from string
public static string getNumberAndCount(string numberStr)
{
var number = "";
int count = 0;
if (numberStr.Length >= 1)
{
while (IsNumber(numberStr[count].ToString()))
{
number += numberStr[count];
if (numberStr.Length == 1)
break;
count++;
}
}
return number + "," + (count == 0 ? count : count - 1);
}
问题:
1)当我正确地应用规则时,为什么它仍然不起作用(我知道我在某个地方犯了错误)
2)如何添加括号支持?
p。S:我必须为一个应用程序做这个…
试着改变这个方法:
private static void CheckPrecedence(char currentOp, ref Stack<double> values, ref Stack<char> operators,
Dictionary<char, int> operatorList)
{
char lastStackOp = operators.Peek();
//if same precedence of both Op are same
//OR lastOp > than CurrentOp
while (((operatorList[lastStackOp] == operatorList[currentOp]) ||
(operatorList[lastStackOp] > operatorList[currentOp])))
{
var TopMostOperand = values.Pop();
var PrevOperand = values.Pop();
var TopMostOperator = operators.Pop();
values.Push(calculateExpression(TopMostOperator, TopMostOperand, PrevOperand));
if (operators.Count == 0)
break;
lastStackOp = operators.Peek();
}
operators.Push(currentOp);
}
问题是,如果你最终在堆栈中计算一个操作符,因为它具有比当前操作更高的优先级,你必须检查堆栈的新头是否也具有比当前操作更高或相等的优先级。我用while循环替换了if语句,继续检查,直到条件不再满足。
我会尝试让括号工作,并将在几分钟内检查回来:)
EDIT (For括号):括号被视为特殊字符,只在关闭后才计算。要使它们工作,向操作符列表添加以下2个值:
{'*',new OperatorInfo('(',"OpenBracket",5,OperatorFixity.Left)},
{'^',new OperatorInfo(')',"CloseBracket",5,OperatorFixity.Left)}
然后改成
else if (IsOperator(expression[i]))
{
//Maintain precedence on stack
if (operators.Count > 0)
{
CheckPrecedence(expression[i], ref values, ref operators, operatorList);
}
else
operators.Push(expression[i]);//runs first time only
}
:
else if (IsOperator(expression[i]))
{
//Maintain precedence on stack
if (operators.Count > 0 && expression[i] != '(' && expression[i] != ')')
{
CheckPrecedence(expression[i], ref values, ref operators, operatorList);
}
else if (expression[i] == ')')
{
while (operators.Peek() != '(')
{
var lastOperator = operators.Pop();
var LastOperand = values.Pop();
var PrevOperand = values.Pop();
values.Push(calculateExpression(lastOperator, LastOperand, PrevOperand));
}
operators.Pop();
}
else
operators.Push(expression[i]);
}