数学表达式求值器中的十进制转换问题

问题描述 投票:0回答:1

我正在用 C# 实现一个数学表达式求值器,但我无法使用十进制数字,例如,如果我输入“3.4”,程序会将其视为“34”。如果使用像“3,4”这样的逗号,问题是一样的。



        static void EvaluateInput(string input)
        {
            string[] parts = input.Split('=');
            if (parts.Length == 2)
            {
                string variableName = parts[0].Trim();
                if (IsValidVariableName(variableName))
                {
                    string expression = parts[1].Trim();

                    double result = SolveExpression(expression);
                    variables[variableName] = SolveExpression(expression);
                    lastResult = result;

                    Console.WriteLine($"{variableName} = {result}");
                }
                else
                {
                    Console.WriteLine("Invalid variable name. Use lowercase letters.");
                }
            }
            else
            {
                double result = SolveExpression(input);
                lastResult = result;
                Console.WriteLine($"  = {result}");
            }
        }

        static bool IsValidVariableName(string variableName)
        {
            return !string.IsNullOrEmpty(variableName) && variableName.Length == 1 && char.IsLower(variableName[0]);
        }

        static double SolveExpression(string expression)
        {
            expression = expression.Replace(',', '.');

            foreach (var constant in constants)
            {
                expression = expression.Replace(constant.Key, constant.Value.ToString(CultureInfo.InvariantCulture));
            }

            expression = Regex.Replace(expression, @"(?<=[^\d\.])-", "-");
            expression = Regex.Replace(expression, @"(?<=\d)-", " -");
            string[] tokens = TokenizeExpression(expression);

            Stack<string> operators = new Stack<string>();
            Stack<double> values = new Stack<double>();

            foreach (string token in tokens)
            {
                if (double.TryParse(token, out double number))
                {
                    values.Push(number);
                }
                else if (IsValidVariableName(token))
                {
                    if (variables.ContainsKey(token))
                    {
                        values.Push(variables[token]);
                    }
                    else
                    {
                        throw new InvalidOperationException($"Undefined variable: {token}");
                    }
                }

                else if (IsOperator(token))
                {
                    while (operators.Count > 0 && Priority(operators.Peek()) >= Priority(token))
                    {
                        if (operators.Peek() == "(")
                            break;

                        if (values.Count >= 2)
                        {
                            double val2 = values.Pop();
                            double val1 = values.Pop();
                            string op = operators.Pop();
                            values.Push(ApplyOperator(op, val1, val2));
                        }
                        else
                        {
                            break;
                        }
                    }
                    operators.Push(token);
                }
                else if (token == "(")
                {
                    operators.Push(token);
                }
                else if (token == ")")
                {
                    while (operators.Peek() != "(")
                    {
                        double val2 = values.Pop();
                        double val1 = values.Pop();
                        string op = operators.Pop();
                        values.Push(ApplyOperator(op, val1, val2));
                    }
                    operators.Pop();
                }
            }

            while (operators.Count > 0)
            {
                if (values.Count >= 2)
                {
                    double val2 = values.Pop();
                    double val1 = values.Pop();
                    string op = operators.Pop();
                    values.Push(ApplyOperator(op, val1, val2));
                }
                else
                {
                    break;
                }
            }

            return values.Count > 0 ? values.Pop() : 0;
        }

        static string[] TokenizeExpression(string expression)
        {
            List<string> tokens = new List<string>();
            string currentToken = "";

            for (int i = 0; i < expression.Length; i++)
            {
                char c = expression[i];

                if (char.IsDigit(c) || c == '.' || c == ',')
                {
                    currentToken += c;
                }
                else
                {
                    if (!string.IsNullOrEmpty(currentToken))
                    {
                        if (double.TryParse(currentToken.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedNumber))
                        {
                            tokens.Add(parsedNumber.ToString(CultureInfo.InvariantCulture));
                        }
                        else
                        {
                            tokens.Add(currentToken);
                        }
                        currentToken = "";
                    }

                    if (IsOperator(c.ToString()) || c == '(' || c == ')')
                    {
                        tokens.Add(c.ToString());
                    }
                    else if (char.IsLetter(c))
                    {
                        currentToken = c.ToString();
                    }
                }
            }

            if (!string.IsNullOrEmpty(currentToken))
            {
                if (double.TryParse(currentToken.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedNumber))
                {
                    tokens.Add(parsedNumber.ToString(CultureInfo.InvariantCulture));
                }
                else
                {
                    tokens.Add(currentToken);
                }
            }

            return tokens.ToArray();
        }

        static bool IsOperator(string token)
        {
            return token == "+" || token == "-" || token == "*" || token == "/" || token == "^";
        }

        static int Priority(string op)
        {
            if (op == "^")
                return 3;
            if (op == "*" || op == "/")
                return 2;
            if (op == "+" || op == "-")
                return 1;
            return 0;
        }

        static double ApplyOperator(string op, double a, double b)
        {
            switch (op)
            {
                case "+": return a + b;
                case "-": return a - b;
                case "*": return a * b;
                case "/": return a / b;
                case "^": return Math.Pow(a, b);
                default: throw new ArgumentException($"Invalid operator: {op}");
            }
        }

我尝试强制代码使用“en-US”全球化,但没有成功。我还尝试了意义上的差异解析将字符串转换为浮点数,也没有成功

c# parsing math expression evaluator
1个回答
0
投票

而不是这样做:

if (double.TryParse(token, out double number))
{
  values.Push(number);
}

试试这个:

if (new Regex(@"\d+(\.\d+)?").IsMatch(token))
{
  values.Push(double.Parse(token, CultureInfo.InvariantCulture));
}

其他

TryParse
可能也需要更改。

© www.soinside.com 2019 - 2024. All rights reserved.