The problematic to resolve:
Given a string that contains a mathematical expression, I need a function on C# language that receives that string and returns its decimal result that respects the operators hierarchy. So for example:
CalculateExpression("10×2-5÷4");
should return 18.75
.
Some considerations:
- My initial approach is based on a stack method by using a Reverse Polish Notation (RPN).
- I'm not taking into consideration parenthesis
( )
nor this caret:^
because for my project case, the user will never be able to type those characters. So for operators, the only ones that would be available are :+
-
×
÷
. - The function should recognize decimals dots, so for example
CalculateExpression("15.4+5.5");
should return20.9
.
What I did:
While it works as I wanted, I'd like to receive feedback on the overall algorithm process, so I can enhance it or maybe there is something I didn't consider that someone would if it is seen or maybe there is already a library that does something done here.
Any tip works.
I tried to put comments on the most important things done and overall, what I'm doing in each section:
private static decimal CalculateInput(string input)
{
//the same input but splitted, so: "10+5" becomes ["10", "+", "5"]
List<string> splittedInput = new List<string>();
//stack for storing operators based on the RPN algorithm
Stack<string> operatorStack = new Stack<string>();
//the same splittedInput but formatted as PostFix, so: [10, +, 5] becomes ["10", "5", "+"]
List<string> splittedPostFixExp = new List<string>();
string strNumber = "";
foreach (char theChar in input)
{//looping through the string to append each operand and operator to the splittedInput List
if (theChar != '+' && theChar != '-' && theChar != '×' && theChar != '÷')
{
strNumber += theChar;
}
else
{
splittedInput.Add(strNumber);
splittedInput.Add(theChar.ToString());
strNumber = string.Empty;
}
}
splittedInput.Add(strNumber);
//formatting the splittedInput to the PostFixed format
foreach (string token in splittedInput)
{
if (token != "+" && token != "-" && token != "×" && token != "÷") //isOperand
{
splittedPostFixExp.Add(token);
}
else
{
if (operatorStack.Count != 0)
{
if ((token == "×" || token == "÷") && (operatorStack.Peek() == "+" || operatorStack.Peek() == "-"))
{//upcoming token has greater precedence than top element on stack
operatorStack.Push(token);
}
else if ((token == "+" || token == "-") && (operatorStack.Peek() == "×" || operatorStack.Peek() == "÷"))
{//upcoming token has lower precedence than top element on stack
PopUntilLowerPrecedence(token);
}
else
{//upcoming token has the same precedence than top element on stack (basically the same as the previous condition)
PopUntilLowerPrecedence(token);
}
}
else
{
operatorStack.Push(token);
}
}
}
while (operatorStack.Count != 0)
{//Poping each operator in the stack to the end of the PostFixExpression
splittedPostFixExp.Add(operatorStack.Pop());
}
void PopUntilLowerPrecedence(string token)
{//function for poping the stack until the token has higher precedence than operatorStack.Peek()
while (operatorStack.Count != 0)
{
if (((token == "×" || token == "÷") && (operatorStack.Peek() == "+" || operatorStack.Peek() == "-")))
{//upcoming token has NOW greater precendence
break;
}
splittedPostFixExp.Add(operatorStack.Pop());
}
operatorStack.Push(token);
}
//calculating result by using the PostFixExpression
for (int i = 0; i < splittedPostFixExp.Count; i++)
{
if (splittedPostFixExp[i] == "+" || splittedPostFixExp[i] == "-" || splittedPostFixExp[i] == "×" || splittedPostFixExp[i] == "÷")
{
decimal left = decimal.Parse(splittedPostFixExp[i - 2]);
decimal right = decimal.Parse(splittedPostFixExp[i - 1]);
decimal result = 0M;
switch (splittedPostFixExp[i])
{
case "+":
result = left + right;
break;
case "-":
result = left - right;
break;
case "×":
result = left * right;
break;
case "÷":
result = left / right;
break;
}
for (int j = i; j > i - 3; j--)
{
splittedPostFixExp.RemoveAt(j);
}
splittedPostFixExp.Insert(i - 2, result.ToString());
i = 0;
}
}
return decimal.Parse(splittedPostFixExp[0]);
}
Thanks in advance! Wishing you a nice day:)