数据结构求表达式的值C#实现版本

考虑了各种可能会出现的bug情况,使用正则表达式或抛异常处理
支持的函数有:
“abs”, “asin”, “acos”, “atan”, “cos”, “pow”, “random”, “sin”, “sqrt”, “tan”, “log”, “ln”
和普通的+ - * /,
也支持有变量,不过变量格式仅允许非数字非普通操作符的各种字符,且默认为1

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace test
{
    class Expression
    {
        public Expression(string exp)
        {
            expressionString = exp;
        }
        public void Run(out string temp, Dictionary<string, double> V)
        {
            temp = expressionString;
            PreDo(temp);
            ClearBlackSpace(ref temp);
            getVariable(temp);
            if (V.Count > 0)
                changeVariableValue(V);
        }
        private string expressionString = string.Empty;
        private static string[] specialOperator = new string[] { "abs", "asin", "acos", "atan", "cos", "pow", "random", "sin", "sqrt", "tan", "log", "ln" };
        private static char[] commonOperator = new char[] { '+', '-', '*', '/', '(', ')', '.', '^', ',', '%' };
        private Dictionary<string, double> variable = new Dictionary<string, double>();//变量字典
        private int specialLongest = 0;
        private void getspecialLongest()
        {
            foreach (var item in specialOperator)
            {
                specialLongest = specialLongest > item.Length ? specialLongest : item.Length;
            }
        }
        private bool CheckBrackets(string str)
        {
            int mark = 0;
            for (int i = 0; i < str.Length; i++)
            {
                if (str[i] == '(')
                {
                    mark += 1;
                }
                if (str[i] == ')')
                {
                    if (mark == 0)
                        return false;
                    else mark -= 1;
                }
            }
            if (mark == 0)
                return true;
            return false;
        }
        private void modifyString(ref string str)//先实现替换(-,增加0,变成(0-,同理(+,后期实现3sin()之间无符号
        {
            if (str.StartsWith("%") || str.StartsWith("^") || str.StartsWith("*") || str.StartsWith("/"))
                throw new Exception("字符串不能以运算符开头");

            if (str.StartsWith("-") || str.StartsWith("+"))
                str = "0" + str;
            foreach (var item in specialOperator)
            {
                str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + item.ToString(), "$1*" + item.ToString());
            }

            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "Math.PI", "$1*Math.PI");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "Math.E", "$1*Math.E");

            str = System.Text.RegularExpressions.Regex.Replace(str, "Math.PI" + @"(\w)", "Math.PI*$1");
            str = System.Text.RegularExpressions.Regex.Replace(str, "Math.E" + @"(\w)", "Math.E*$1");

            str = System.Text.RegularExpressions.Regex.Replace(str, "Math.PI", Math.PI.ToString());
            str = System.Text.RegularExpressions.Regex.Replace(str, "Math.E", Math.E.ToString());

            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)" + "\\(", "$1*(");
            str = System.Text.RegularExpressions.Regex.Replace(str, "\\)" + "\\(", ")*(");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\d)([a-zA-Z])", "$1*$2");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"([a-zA-Z])(\d)", "$1*$2");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"([\\~\\!\\@\\#\\$\\&\\=\\?\\>\\<\\:\\;\\'""])(\w)", "$1*$2");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)([\\~\\!\\@\\#\\$\\&\\=\\?\\>\\<\\:\\;\\'""])", "$1*$2");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"([\\~\\·\\!\\@\\#\\¥\\&\\(\\)\\?\\/\\。\\,\\|\\、\\/\\:\\;\\'\\“\\”])(\w)", "$1*$2");
            str = System.Text.RegularExpressions.Regex.Replace(str, @"(\w)([\\~\\·\\!\\@\\#\\¥\\&\\(\\)\\?\\/\\。\\,\\|\\、\\/\\:\\;\\'\\“\\”])", "$1*$2");
            str = str.Replace("(-", "(0-");
            str = str.Replace("(+", "(0+");
        }
        //先判断是否为空
        private void PreDo(string exp)
        {
            if (string.IsNullOrEmpty(exp))
            {
                throw new Exception("表达式为空");
            }
            if (!CheckBrackets(exp))
            {
                throw new Exception("括号不匹配");
            }
            getspecialLongest();
        }
        //求变量,组成字典
        private void modifyVariableDict(ref Dictionary<string, double> variable)
        {
            Dictionary<string, double> dic1desc2
             = (from d in variable
                orderby d.Key.Length descending
                select d).ToDictionary(k => k.Key, v => v.Value);
            variable = new Dictionary<string, double>(dic1desc2);
        }
        private void getVariable(string exp)
        {
            string tempString = exp;
            tempString = System.Text.RegularExpressions.Regex.Replace(tempString, @"\d", "");

            foreach (var item in specialOperator)
            {
                tempString = tempString.Replace(item + "(", "");
            }

            string[] strs = tempString.Split(commonOperator);

            foreach (var item in strs)
            {
                if (item != " " && item != "" && !variable.ContainsKey(item))
                    variable.Add(item, 1);
            }
            modifyVariableDict(ref variable);
        }
        public Dictionary<string, double> displayVariable()
        {
            return this.variable;
        }
        private bool isInVariable(string str)
        {
            foreach (var obj in variable)
            {
                if (obj.Key.Equals(str))
                    return true;
            }
            return false;
        }
        public void changeVariableValue(Dictionary<string, double> V)
        {
            foreach (var item in V)
            {
                if (isInVariable(item.Key))
                {
                    variable[item.Key] = item.Value;
                }
            }
        }
        //预处理字符串,去除表达式为空,括号不匹配等问题
        private void ClearBlackSpace(ref string exp)
        {
            exp = exp.Replace(" ", "").Replace("\t", "").Replace("\r", "").Replace("\n", "");
            if (string.IsNullOrEmpty(exp))
            {
                throw new Exception("表达式为空");
            }
            modifyString(ref exp);
        }
        //重构string 
        //参数值传入字符串,用参数值替换参数
        private void addValueToString(ref string exp, Dictionary<string, double> V)
        {
            foreach (var item in variable)
            {
                string pattern = string.Empty;

                if (item.Key != "?" && item.Key != "$")
                    pattern = item.Key + "(?=[^(])";
                else
                    pattern = "\\" + item.Key + "(?=[^(])";

                Regex regex = new Regex(pattern);
                string result = string.Empty;
                result = regex.Replace(exp, "(" + item.Value + ")");

                if (item.Key != "?" && item.Key != "$")
                    pattern = item.Key + "$";
                else
                    pattern = "\\" + item.Key + "$";

                regex = new Regex(pattern);
                result = regex.Replace(result, "(" + item.Value + ")");
                exp = result;
            }
        }
        private bool isNum(char c)
        {
            return (c >= '0' && c <= '9');
        }
        private bool isInCommonOperator(char ch)
        {
            foreach (var item in commonOperator)
            {
                if (item.Equals(ch))
                {
                    return true;
                }
            }
            return false;
        }
        private bool isInSpecialOperator(string c)
        {
            foreach (var item in specialOperator)
            {
                if (item.Equals(c))
                {
                    return true;
                }
            }
            return false;
        }
        //判断优先级
        private char Precede(char a, char b)
        {
            switch (a)
            {
                case '^':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '>';
                            case '/': return '>';
                            case '(': return '<';
                            case ')': return '>';
                            case '#': return '>';
                            case '%': return '>';
                            case '^': return '>';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '%':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '>';
                            case '/': return '>';
                            case '(': return '<';
                            case ')': return '>';
                            case '#': return '>';
                            case '^': return '<';
                            case '%': return '>';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '+':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '<';
                            case '/': return '<';
                            case '(': return '<';
                            case ')': return '>';
                            case '#': return '>';
                            case '^': return '<';
                            case '%': return '<';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '-':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '<';
                            case '/': return '<';
                            case '(': return '<';
                            case ')': return '>';
                            case '^': return '<';
                            case '#': return '>';
                            case '%': return '<';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '*':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '>';
                            case '/': return '>';
                            case '(': return '<';
                            case ')': return '>';
                            case '^': return '<';
                            case '%': return '>';
                            case '#': return '>';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '/':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '>';
                            case '/': return '>';
                            case '(': return '<';
                            case ')': return '>';
                            case '#': return '>';
                            case '^': return '<';
                            case '%': return '>';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '(':
                    {
                        switch (b)
                        {
                            case '+': return '<';
                            case '-': return '<';
                            case '*': return '<';
                            case '/': return '<';
                            case '(': return '<';
                            case ')': return '=';
                            case '^': return '<';
                            case '%': return '<';
                            // case ',': return '>';
                            default: return ' ';
                        }
                    }

                case ')':
                    {
                        switch (b)
                        {
                            case '+': return '>';
                            case '-': return '>';
                            case '*': return '>';
                            case '/': return '>';
                            case ')': return '>';
                            case '^': return '>';
                            case '#': return '>';
                            case '%': return '>';
                            case ',': return '>';
                            default: return ' ';
                        }
                    }

                case '#':
                    {
                        switch (b)
                        {
                            case '+': return '<';
                            case '-': return '<';
                            case '*': return '<';
                            case '/': return '<';
                            case '(': return '<';
                            case '#': return '=';
                            case '^': return '<';
                            case '%': return '<';
                            default: return ' ';
                        }
                    }

                default:
                    return ' ';

            }
        }
        private double Operate(double a = 0.0, char c = ' ', double b = 0.0)
        {
            switch (c)
            {
                case '+': return (a + b);
                case '-': return (a - b);
                case '*': return (a * b);
                case '/': return (a / b);
                case '^': return Math.Pow(a, b);
                case '%': return a % (b > 0 ? b : 1);
                default: return 0.0;
            }
        }
        private double SpecialOperate(string s, double a, double b = 0.0)
        {//"abs", "asin", "acos", "atan", "cos", "pow", "random", "sin", "sqrt", "tan"
            switch (s)
            {
                case "abs":
                    {
                        return Math.Abs(a);
                    }
                case "asin":
                    {
                        return Math.Asin(a);
                    }
                case "acos":
                    {
                        return Math.Acos(a);
                    }
                case "atan":
                    {
                        return Math.Atan(a);
                    }
                case "cos":
                    {
                        return Math.Cos(a);
                    }
                case "ln":
                    {
                        return Math.Log(a);
                    }
                case "pow":
                    {
                        return Math.Pow(b, a);
                    }
                case "log":
                    {
                        if (b > 0 && b != 1)
                        {
                            return Math.Log(a, b);
                        }
                        else
                            return 0.0;
                    }
                case "random":
                    {
                        double m_max = a > b ? a : b;
                        double m_min = a < b ? a : b;
                        int min = Convert.ToInt32(m_min);
                        int max = Convert.ToInt32(m_max);
                        return new Random().Next(min, max);
                    }
                case "sin":
                    {
                        return Math.Sin(a);
                    }
                case "sqrt":
                    {
                        if (a < 0) throw new Exception("sqrt函数输入参数不能小于0");
                        return Math.Sqrt(a);
                    }
                case "tan":
                    {
                        return Math.Tan(a);
                    }
                default:
                    {
                        return 0.0; //控制不会走到这里
                    }
            }
        }

        private Stack<char> operateStack = new Stack<char>();//运算符
        private Stack<double> numberStack = new Stack<double>();//数字
        private Stack<string> specialOperateStack = new Stack<string>();//特殊运算符       
        private List<char> StringToList(string str)
        {
            List<char> lst = new List<char>();
            foreach (var item in str)
            {
                lst.Add(item);
            }
            return lst;
        }
        //判断对应的(是不是特殊符号的(,如果是特殊运算
        private bool isMatchSpecialLeftBrackets(List<char> temp, int leftIndex)
        {
            return (leftIndex > 0 && temp[leftIndex].Equals('(') && !isInCommonOperator(temp[leftIndex - 1]));
        }
        //)对应的(
        private int LocateMatchIndex(List<char> temp, int rightIndex)
        {
            int mark = 1;
            for (int i = rightIndex - 1; i >= 1; i--)
            {
                if (temp[i] == ')')
                    mark += 1;
                else if (temp[i] == '(')
                    mark -= 1;
                if (mark == 0)
                    return i;
            }
            return -1;
        }
        //符合:
        //+(   -(   *(   /(((    ^(    , (    %(
        //()
        //)+    )-    )*    )/      ))   )^     )%   ), 
        private bool isDoubleCommonEnableTeam(char a, char b)
        {
            if (a == '.' || b == '.')
                return false;
            if (isInCommonOperator(a) && b == '(')
                return true;
            else if (b != '(' && isInCommonOperator(b) && a == ')')
                return true;
            else if (a.Equals('(') && b.Equals(')'))
                return true;
            else return false;
        }
        private void CommonOperatorNotMatchWarning(int current, List<char> expChar, char ch)
        {
            if ((operateStack.Peek() == '(' && ch == '#') || (operateStack.Peek() == ')' && ch == '(') || (operateStack.Peek() == '#' && ch == ')'))
                throw new Exception("符号不匹配");
            if (current > 0 && isInCommonOperator(expChar[current - 1]) && isInCommonOperator(ch))
            {
                if (!isDoubleCommonEnableTeam(expChar[current - 1], ch))
                    throw new Exception("符号不匹配");
            }

        }
        //计算表达式
        public double Calculate(Dictionary<string, double> V)
        {
            string exp;
            Run(out exp, V);
            addValueToString(ref exp, V);
            modifyString(ref exp);
            bool num_realm = false;
            bool xiaoshu_realm = false;
            int xiaoshu_weishu = 0;
            int pointOccurTime = 0;//避免搞事情,出现多个点
            List<char> expChar = StringToList(exp);
            expChar.Add('#'); // 借助特俗标志#来控制结束
            int specialRealm = 0;//既做标志位,也做次数判断

            int current = 0;
            char ch = expChar[current];
            operateStack.Push('#');

            //先入栈
            while (ch != '#' || operateStack.Peek() != '#')
            {
                if (isNum(ch))
                {
                    if (num_realm && !xiaoshu_realm)//二位数或更多位数
                    {
                        double e = numberStack.Pop();
                        int newNum = (int)(ch - '0');
                        //e = e * 10 + (e > 0 ? newNum : -1 * newNum);
                        e = e * 10 + newNum;
                        numberStack.Push(e);
                    }
                    else if (num_realm && xiaoshu_realm)//小数部分
                    {
                        xiaoshu_weishu += 1;
                        double e = numberStack.Pop();
                        double newNum = (int)(ch - '0') * Math.Pow(0.1, xiaoshu_weishu);
                        //  e = e + (e > 0 ? newNum : -1 * newNum);
                        e += newNum;
                        numberStack.Push(e);
                    }
                    else//第一位整数
                    {
                        numberStack.Push(ch - '0');
                        num_realm = true;
                    }
                    if (current < expChar.Count - 1)
                    {
                        ch = expChar[++current];
                    }
                }
                else
                {
                    if (num_realm && ch == '.')
                    {
                        pointOccurTime += 1;
                        if (pointOccurTime < 2)
                        {
                            xiaoshu_realm = true;
                            if (current < expChar.Count - 1)
                            {
                                ch = expChar[++current];
                            }
                        }
                        else
                        {
                            throw new Exception("出现多个小数点的错误");
                        }
                    }
                    else if (isInCommonOperator(ch) || ch.Equals('#'))//常规运算符或结束符号
                    {
                        pointOccurTime = xiaoshu_weishu = 0;
                        num_realm = xiaoshu_realm = false;
                        CommonOperatorNotMatchWarning(current, expChar, ch);
                        switch (Precede(operateStack.Peek(), ch))
                        {
                            case '<': //后面的大,压入
                                {
                                    operateStack.Push(ch);
                                    if (current < expChar.Count - 1)
                                    {
                                        ch = expChar[++current];
                                    }
                                    break;
                                }
                            case '>':
                                {
                                    if (numberStack.Count >= 2)
                                    {
                                        char theta;
                                        double a, b;
                                        a = numberStack.Pop();
                                        b = numberStack.Pop();
                                        theta = operateStack.Pop();
                                        numberStack.Push(Operate(b, theta, a));
                                    }
                                    break;
                                }
                            case '=':
                                {
                                    operateStack.Pop();
                                    int indexOfRight = current;
                                    int leftIndex = LocateMatchIndex(expChar, current);
                                    if (isMatchSpecialLeftBrackets(expChar, leftIndex) && specialRealm > 0)
                                    {
                                        specialRealm -= 1;
                                        double num1 = numberStack.Pop();
                                        if (specialOperateStack.Peek() != "random" && specialOperateStack.Peek() != "pow" && specialOperateStack.Peek() != "log")
                                        {
                                            numberStack.Push(SpecialOperate(specialOperateStack.Pop(), num1));
                                        }
                                        else
                                        {
                                            double num2 = numberStack.Pop();
                                            numberStack.Push(SpecialOperate(specialOperateStack.Pop(), num1, num2));
                                        }
                                    }


                                    if (current < expChar.Count - 1)
                                    {
                                        ch = expChar[++current];
                                    }
                                    break;
                                }
                            default: { break; }
                        }
                        if (ch == ',' && current < expChar.Count - 1)
                        {
                            ch = expChar[++current];
                        }
                        else if (ch == '.' && current >= expChar.Count - 1)
                        {
                            throw new Exception("溢出或字符串匹配不正确");
                        }
                    }
                    else//特殊运算符
                    {
                        StringBuilder specialBuilder = new StringBuilder();
                        specialBuilder.Append(ch.ToString());
                        while (!isInSpecialOperator(specialBuilder.ToString()) && current < expChar.Count - 1 && specialBuilder.Length <= specialLongest)
                        {
                            ch = expChar[++current];
                            specialBuilder.Append(ch.ToString());
                        }
                        if (!isInSpecialOperator(specialBuilder.ToString()))
                            throw new Exception("出现未知异常");
                        else
                        {
                            specialOperateStack.Push(specialBuilder.ToString());
                            specialRealm += 1;
                        }
                        ch = expChar[++current];
                    }
                }
            }
            return numberStack.Peek();
        }
    }

    public class totalData//包含变量和字符串的类结构
    {
        private string exp;
        public totalData(string s)
        {
            exp = s;
            string temp = exp;
            Expression e = new Expression(exp);
            e.Run(out temp, new Dictionary<string, double>());
            this.temporaryDict = e.displayVariable();
        }
        public void changeVariable(Dictionary<string, double> t)
        {
            string temp = exp;
            Expression e = new Expression(exp);
            e.Run(out temp, t);
            this.temporaryDict = e.displayVariable();
        }
        private Dictionary<string, double> temporaryDict;
        public double operationResult()
        {
            return new Expression(exp).Calculate(temporaryDict);
        }
        public Dictionary<string, double> getVariableDict()
        {
            return this.temporaryDict;
        }
    }
    class Program
    {
        static void Main(String[] args)
        {
            string s = Console.ReadLine();
            Console.WriteLine(new totalData(s).operationResult().ToString("0.00"));
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

广大菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值