首页 > 解决方案 > 相同的算法一次有效,第二次出错

问题描述

好吧,在我得到答案之前,这个问题可能会被关闭......我正在尝试编写一个非常简单的计算器,它可以完美地工作:

private void button1_Click(object sender, EventArgs e)
        {
            string[] input = rtbInput.Text.Split(' ');
            rtbInput.Text += " = " + CalculateNumber(input).ToString();
        }

long CalculateNumber(string[] input)
        {
            long curValue = 0;
            curValue = long.Parse(input[0]);
            //LOOK FOR PARENTHASIS, LAST INDEX, SEARCH FROM THERE UNTIL FIRST INDEX, RUN THIS AGAIN FOR THAT.
            //THEN REPLACE "5 + (3 + 3)" with 5 + 6. So calculate 3 + 3 = 6 and replace ( until ) with answer.
            if (rtbInput.Text.Contains("(") && rtbInput.Text.Contains(")"))
            {
                int c = 0;
                int startNum;
                int len;
                string s = "No";
            }

            int i = 0;
            while (i < (input.Length - 1))
            {
                switch (input[i])
                {
                    case "+":
                        curValue += long.Parse(input[i + 1]);
                        break;
                    case "-":
                        curValue -= long.Parse(input[i + 1]);
                        break;
                    case "*":
                        curValue = curValue * long.Parse(input[i + 1]);
                        break;
                    case "/":
                        curValue = curValue / long.Parse(input[i + 1]);
                        break;
                }
                i++;
            }

            return curValue;
        }

这非常有效。但是当尝试添加计算Parenthasis“(3 * 3)= 9”的能力时,我实现了这个代码:

long CalculateNumber(string[] input)
        {
            long curValue = 0;
            curValue = long.Parse(input[0]);
            //LOOK FOR PARENTHASIS, LAST INDEX, SEARCH FROM THERE UNTIL FIRST INDEX, RUN THIS AGAIN FOR THAT.
            //THEN REPLACE "5 + (3 + 3)" with 5 + 6. So calculate 3 + 3 = 6 and replace ( until ) with answer.
            if (rtbInput.Text.Contains("(") && rtbInput.Text.Contains(")"))
            {
                int c = 0;
                int startNum;
                int len;
                string s = "No";
                //while there are still parenthasis in the input, do this
                if (c < rtbInput.Text.Split('(').Count() - 1)       //REPLACE WITH WHILE
                {
                    startNum = rtbInput.Text.LastIndexOf('(') + 1;
                    len = rtbInput.Text.IndexOf(')', startNum);// - startNum;
                    s = rtbInput.Text.Substring(startNum, len);
                    this.Name = s;
                    //NOW REPLACE THIS WITH THE RETURN OF CalculateParenthasis.Split(' ')
                    rtbInput.Text = rtbInput.Text.Replace("(" + s + ")", CalculateParenthasis(s.Split(' ')).ToString());
                }

long CalculateParenthasis(string[] input)
        {
            long curValue = 0;
            curValue = long.Parse(input[0]);
            button1.Text += curValue.ToString();
            int i = 0;
            while (i < (input.Length - 1))
            {
                switch (input[i])
                {
                    case "+":
                        curValue += long.Parse(input[i + 1]);
                        break;
                    case "-":
                        curValue -= long.Parse(input[i + 1]);
                        break;
                    case "*":
                        curValue = curValue * long.Parse(input[i + 1]);
                        break;
                    case "/":
                        curValue = curValue / long.Parse(input[i + 1]);
                        break;
                }
                i++;
            }

            return curValue;
        }

正如您所看到的,CalculateParenthasis() 函数的工作方式与 CalculateNumber() 完全相同,但采用括号之间的数字,但在 switch 语句中出现此错误,表示输入字符串的格式错误?什么?我几乎不知道如何问这个问题,似乎是一件很小很容易出错的事情,但我就是看不到。

标签: c#visual-studio

解决方案


根据我的测试,我重现了您遇到的问题。

但是,我发现由于它的复杂性,我们很难完成它。

因此,我建议您使用反向波兰算法来制作计算器。

我做了一个代码示例来制作它,你可以参考它。

代码:

public class Example
    {
        public static Stack<string> operStack = new Stack<string>();
        public static Stack<string> numStack = new Stack<string>();
        static bool IsNumber(string s)
        {
            return Regex.IsMatch(s, @"\d+");
        }

        static bool IsSiZe(string s)
        {
            string ts = "+-*/";
            return ts.IndexOf(s) > -1;
        }

        static int Level(string s)
        {
            int i = 0;
            switch (s)
            {
                case ",":
                    i = 0;
                    break;
                case "(":
                case ")":
                case "#":
                    i = 1;
                    break;
                case "+":
                case "-":
                    i = 2;
                    break;
                case "*":
                case "/":
                    i = 3;
                    break;
            }
            return i;
        }

        public static void Calc(Stack<string> numStack, Stack<string> operStack)
        {
            int rightnum = int.Parse(numStack.Pop());
            int leftnum = int.Parse(numStack.Pop());
            string oper = operStack.Pop();
            switch (oper)
            {
                case "+":
                    numStack.Push((leftnum + rightnum).ToString());
                    break;
                case "-":
                    numStack.Push((leftnum - rightnum).ToString());
                    break;
                case "*":
                    numStack.Push((leftnum * rightnum).ToString());
                    break;
                case "/":
                    numStack.Push((leftnum / rightnum).ToString());
                    break;
            }
       
        }

        public static void ToNiBoLan(string exp)
        {

            operStack.Push("#");  //Push into the stack  for comparsion

            string token = "";
            for (int i = 0; i < exp.Length; i++)
            {
                if (IsNumber(exp[i].ToString()))  //If it is number
                {
                    token += exp[i].ToString();
                }
                else if (exp[i].ToString() == "(")   
                {
                    operStack.Push(exp[i].ToString());
                    if (IsNumber(token))
                        numStack.Push(token);
                    token = "";
                }
                else if (IsSiZe(exp[i].ToString()))
                {
                    if (IsNumber(token))
                        numStack.Push(token);
                    token = "";
                    int item = Level(exp[i].ToString()).CompareTo(Level(operStack.Peek()));  //Comparison operator precedence
                    if (item > 0)  //If the priority is higher than the top of the stack, the operator is pushed onto the stack
                    {
                        operStack.Push(exp[i].ToString());
                    }
                    else   //If the operator is less than or equal to the top of the stack, calculate and push the operator onto the stack
                    {

                        Calc(numStack, operStack);

                        operStack.Push(exp[i].ToString());
                    }

                }
                else if (exp[i].ToString() == ")")  
                {
                    if (IsNumber(token))
                        numStack.Push(token);
                    token = "";
                    while (operStack.Peek() != "(")
                    {
                        Calc(numStack, operStack);
                    }
                    token = numStack.Pop();  //Take out the numbers for the next calculation
                    operStack.Pop();  //Eligible left parenthesis popped

                }
                else  //End of traversal
                {
                    if (IsNumber(token))
                        numStack.Push(token);
                    token = "";
                    while (numStack.Count > 1)
                    {
                        Calc(numStack, operStack);
                    }
                }
            }
        }

    }

在winforms中使用它:

  private void button1_Click(object sender, EventArgs e)
        {
            //For comparison, add "#" at the end of the expression
            string text = richTextBox1.Text.Trim() + "#";
            Example.ToNiBoLan(text);
            richTextBox1.Text = Example.numStack.Pop().ToString();
        }

此外,您可以参考链接Reverse Polish notation C# don't work correct


推荐阅读