函数、表达式计算值

    public static class ExpressionEvaluation
    {
        /// <summary>
        /// 计算表达式的值
        /// </summary>
        /// <param name="str">没有语法错误的表达式</param>
        /// <returns>表达式的值</returns>
        public static double ComputeExpressionValue(String str)
        {
            List<string> funcNameList = new List<string> { "Max", "Min" };
            Func<List<string>, bool> HasFuncName = (List<string> funcList) =>
            {
                bool hasFunc = false;
                for (var pos = 0; pos < funcNameList.Count; ++pos)
                {
                    if (funcList.Contains(funcNameList[pos]))
                    {
                        hasFunc = true;
                        break;
                    }
                }
                return hasFunc;
            };
            List<String> postFix = null;
            List<String> expressList = stringToArray(funcNameList,str);
            if (HasFuncName(expressList))
            {
                do
                {
                    var preExpress = PretreatmentExpression(funcNameList,expressList);
                    expressList = preExpress;
                }
                while (HasFuncName(expressList));
                postFix = InfixConvertToPostfix(expressList);
            }
            else
            {
                postFix = InfixConvertToPostfix(expressList);
            }

            return PostExpressValue(postFix);
        }

        private static double PostExpressValue(List<String> postFix)
        {
            Stack<double> num = new Stack<double>();
            double num1 = 0;  // 接收栈顶数
            double num2 = 0;  // 接收次顶数
            double res = 0;  // 每次计算结果
            foreach (String s in postFix)
            {
                if (s == "0")
                {
                    num.Push(double.Parse(s));
                }
                else
                {
                    string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
                    Match match1 = Regex.Match(s, regexStr1);
                    if (match1.Success)
                    {    // 如果是数,就压栈
                        num.Push(double.Parse(s));
                    }
                    else
                    {
                        num1 = num.Pop();
                        num2 = num.Pop();
                        switch (s)
                        {
                            case "+":
                                res = num2 + num1;
                                break;
                            case "-":
                                res = num2 - num1;
                                break;
                            case "*":
                                res = num2 * num1;
                                break;
                            case "/":
                                res = num2 / num1;
                                break;
                            default:
                                throw new Exception("扫描到未知符号!");
                        }
                        num.Push(res);
                    }
                }

            }
            return num.Pop();
        }

        private static bool isOperator(char c)
        {
            // 只有当遍历到以下符号时,才存储集合,其他符号过滤
            return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
        }

        private static bool isNumber(char c)
        {
            // ascll码中数字 0 ~ 9 对应 48 ~ 57
            return 48 <= c && c <= 57;
        }

        private static int getPriority(String s)
        {
            if (s.Equals("*") || s.Equals("/"))
            {
                return 2;
            }

            if (s.Equals("+") || s.Equals("-"))
            {
                return 1;
            }

            if (s.Equals("("))
            {
                return 0;
            }

            throw new Exception("扫描到未知符号!");
        }

        /// <summary>
        /// 字符串拆分
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static List<String> stringToArray(List<String>funcNameList,String s)
        {
            List<String> ls = new List<String>();
            int i = 0;  // 遍历 String 的索引
            String str;     // 拼接多位数
            char c;     // 每次遍历到的字符
            do
            {
                c = s.ElementAt(i);
                if (c == ' ')
                {
                    i++;
                }
                else
                {
                    if (isOperator(c))
                    {  // 如果遍历到的是符号,直接添加到 list
                        ls.Add("" + c);
                        i++;
                    }
                    else
                    {
                        if (isNumber(c))
                        { //  如果遍历到的是一个数,需要判断是否为多位数,用 str 拼接
                            str = "";  // 先将 str 清空
                            string subStr = s.Substring(i);
                            string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
                            Match match1 = Regex.Match(subStr, regexStr1);
                            if (match1.Success)
                            {
                                str = match1.Value;
                            }
                            else
                            {
                                str = s.Substring(i, 1);
                            }
                            ls.Add(str);
                            i += str.Count();
                        }
                        else
                        {
                            str = "";  // 先将 str 清空
                            string subStr = s.Substring(i);
                            foreach (var funcName in funcNameList)
                            {
                                var leftstr = subStr.ToLower();
                                var func = funcName.ToLower();
                                if (leftstr.StartsWith(func))
                                {
                                    str = funcName;
                                }
                            }
                            if (str != "")
                            {//无效的字符
                                ls.Add(str);
                                i += str.Count();
                            }
                            else
                            {
                                i++;
                            }
                        }
                    }
                }
            } while (i < s.Count());
            return ls;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="infix"></param>
        /// <returns></returns>
        private static List<String> PretreatmentExpression(List<string> funcNameList,List<string> infix)
        {
            List<int> funcExist = new List<int>();
            for (var pos = 0; pos < funcNameList.Count;++pos)
            {
                var funcIndex = infix.FindIndex(it => it.Equals(funcNameList[pos]));
                funcExist.Add(funcIndex);
            }
            int startFuncIndex = int.MaxValue;
            for (var pos = 0;pos < funcExist.Count;pos++ )
            {
                if (funcExist[pos] != -1)
                {
                    if (startFuncIndex > funcExist[pos])
                    {
                        startFuncIndex = funcExist[pos];
                    }
                }
            }
            if (startFuncIndex != int.MaxValue)
            {
                string func = funcNameList[startFuncIndex];
                int index = startFuncIndex;
                int endPos = -1;
                int startCount = 0;
                for (var i = index + 1; i < infix.Count; ++i)
                {
                    if (infix.ElementAt(i).Equals("("))
                    {
                        startCount++;
                    }
                    else
                    {
                        if (infix.ElementAt(i).Equals(")"))
                        {
                            startCount--;
                        }
                    }
                    if (startCount == 0)
                    {
                        endPos = i;
                        break;
                    }
                }
                if (endPos != -1)
                {
                    List<String> s2 = new List<String>();
                    //获取函数参数
                    for (int i = index + 2; i < endPos; ++i)
                    {
                        s2.Add(infix[i]);
                    }
                    //有参函数
                    if (s2.Count != 0)
                    {
                        //判断是否有函数
                        bool hasFunc = false;
                        for (var pos = 0; pos < funcNameList.Count; ++pos)
                        {
                            if (s2.Contains(funcNameList[pos]))
                            {
                                hasFunc = true;
                                break;
                            }
                        }
                        if (hasFunc)
                        {
                            List<String> rtn = new List<String>();
                            for (var i = 0; i < index; ++i)
                            {
                                rtn.Add(infix[i]);
                            }
                            var subList = PretreatmentExpression(funcNameList,s2);

                            List<String> expressValList = new List<string>();
                            List<List<String>> expressList = new List<List<String>>();
                            GetSubExpress(subList, ref expressList);
                            foreach (var express in expressList)
                            {
                                if (express.Count == 1)
                                {
                                    expressValList.Add(express[0]);
                                }
                                else
                                {
                                    var postFix = InfixConvertToPostfix(express);
                                    double val = PostExpressValue(postFix);
                                    expressValList.Add(val.ToString());
                                }
                            }
                            switch (func)
                            {
                                case "Max":
                                    {
                                        double max = GetMaxValue(expressValList);
                                        string maxStr = max.ToString();
                                        rtn.Add(maxStr);
                                    }
                                    break;
                                case "Min":
                                    {
                                        double min = GetMinValue(expressValList);
                                        string minStr = min.ToString();
                                        rtn.Add(minStr);
                                    }
                                    break;
                            }
                            for (var i = endPos + 1; i < infix.Count; ++i)
                            {
                                rtn.Add(infix[i]);
                            }

                            return rtn;
                        }
                        else
                        {
                            List<String> rtn = new List<String>();
                            for (var i = 0; i < index; ++i)
                            {
                                rtn.Add(infix[i]);
                            }
                            List<String> expressValList = new List<string>();
                            if (s2.Count == 1)
                            {
                                expressValList.Add(s2[0]);
                            }
                            else
                            {
                                List<List<String>> expressList = new List<List<String>>();
                                GetSubExpress(s2, ref expressList);
                                foreach (var express in expressList)
                                {
                                    if (express.Count == 1)
                                    {
                                        expressValList.Add(express[0]);
                                    }
                                    else
                                    {
                                        var postFix = InfixConvertToPostfix(express);
                                        double val = PostExpressValue(postFix);
                                        expressValList.Add(val.ToString());
                                    }
                                }
                            }
                            switch (func)
                            {
                                case "Max":
                                    {
                                        double max = GetMaxValue(expressValList);
                                        string maxStr = max.ToString();
                                        rtn.Add(maxStr);
                                    }
                                    break;
                                case "Min":
                                    {
                                        double min = GetMinValue(expressValList);
                                        string minStr = min.ToString();
                                        rtn.Add(minStr);
                                    }
                                    break;
                            }
                            for (var i = endPos + 1; i < infix.Count; ++i)
                            {
                                rtn.Add(infix[i]);
                            }
                            return rtn;
                        }
                    }
                }
                else
                {
                    throw new Exception("");
                }
            }
            return infix;
        }

        private static void GetSubExpress(List<string> s2, ref List<List<string>> expressValList)
        {
            string regexStr1 = @"([1-9]\d*\.\d*|0\.\d*[1-9]\d*)|[1-9]\d*";
            int index = 0;
            for (;index < s2.Count - 1;++index)
            {
                Match match1 = Regex.Match(s2[index], regexStr1);
                Match match2 = Regex.Match(s2[index +1], regexStr1);
                List<string> express = new List<string>();
                if (match1.Success && match2.Success || match1.Success && s2[index + 1] == "0" || match2.Success && s2[index] == "0" || s2[index] == "0" && s2[index + 1] == "0")
                {
                    express.Add(s2[index]);
                    expressValList.Add(express);
                    continue;
                }
                int pos = index;
                while (pos < s2.Count - 1)
                {
                    express.Add(s2[pos]);
                    Match match3 = Regex.Match(s2[pos], regexStr1);
                    Match match4 = Regex.Match(s2[pos + 1], regexStr1);
                    if (match3.Success && match4.Success || match3.Success && s2[pos + 1] == "0" || match4.Success && s2[pos] == "0" || s2[pos] == "0" && s2[pos + 1] == "0")
                    {
                        break;
                    }
                    pos++;
                }
                if (pos == s2.Count - 1)
                {
                    express.Add(s2[pos]);
                }
                expressValList.Add(express);
                index = pos;
            }
            if (index == s2.Count - 1)
            {
                List<string> express = new List<string> { s2[index] };
                expressValList.Add(express);
            }
        }

        private static double GetMinValue(List<string> s2)
        {
            if (s2.Count == 2)
            {
                double v1 = double.Parse(s2[0]);
                double v2 = double.Parse(s2[1]);
                return v1 < v2 ? v1 : v2;
            }
            else
            {
                if (s2.Count == 1)
                {
                    double v1 = double.Parse(s2[0]);
                    return v1;
                }
                else
                {
                    double v1 = double.Parse(s2[s2.Count - 1]);
                    s2.RemoveAt(s2.Count - 1);
                    var v2 = GetMinValue(s2);
                    return v1 < v2 ? v1 : v2;
                }
            }
        }

        private static double GetMaxValue(List<string> s2)
        {
            if (s2.Count == 2)
            {
                double v1 = double.Parse(s2[0]);
                double v2 = double.Parse(s2[1]);
                return v1 > v2 ? v1 : v2;
            }
            else
            {
                if (s2.Count == 1)
                {
                    double v1 = double.Parse(s2[0]);
                    return v1;
                }
                else
                {
                    double v1 = double.Parse(s2[s2.Count - 1]);
                    s2.RemoveAt(s2.Count - 1);
                    var v2 = GetMaxValue(s2);
                    return v1 > v2 ? v1 : v2;
                }
            }
        }

        /// <summary>
        /// 字符串转换为后缀表达式
        /// </summary>
        /// <param name="infix"></param>
        /// <returns></returns>
        private static List<String> InfixConvertToPostfix(List<String> express)
        {
            // 创建两个栈,s1 用于存储临时符号
            Stack<String> s1 = new Stack<String>();
            // s2 由于没有 pop 操作,并且最终需要逆序输出,所以使用 ArrayList 代替之
            List<String> s2 = new List<String>();
            //遍历传入的中缀表达式集合
            foreach (String s in express)
            {
                string regexStr1 = @"[1-9]\d*\.\d*|0\.\d*[1-9]\d*|[1-9]\d*";
                Match match1 = Regex.Match(s, regexStr1);
                if (match1.Success)
                {//正则匹配,匹配到数字,直接添加到 s2
                    s2.Add(match1.Value);
                }
                else if (s.Equals("("))
                {  // 遍历到 (,直接压入 s1
                    s1.Push(s);
                }
                else if (s.Equals(")"))
                {  // 遍历到 ) ,弹出 s1 中的符号添加到 s2 中,直至遇到 (
                    while (s1.Peek().Equals("(") == false)
                    {  // peek() 查看栈顶元素
                        s2.Add(s1.Pop());
                    }
                    s1.Pop();  // 当 ( 弹出,消除小括号
                }
                else
                {  // 遍历到 + - * /
                   // s1 不为空,且当遍历到的符号,小于等于栈顶符号优先级,需要弹栈操作
                   // 直到当前符号优先级大于 s1 栈顶元素或 s1 弹空时,结束
                    while (s1.Count != 0 && (getPriority(s) <= getPriority(s1.Peek())))
                    {
                        s2.Add(s1.Pop());  // 将 s1 栈顶符号弹出添加到 s2 中
                    }
                    // 比较结束后,将当前字符压入 s1 中
                    s1.Push(s);
                }
            }

            // 将 s1 中剩余符号添加到 s2 中
            while (s1.Count != 0)
            {
                s2.Add(s1.Pop());
            }
            return s2;
        }
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值