• 表达式计算器的实现


    一、前言

        关于表达式计算器的实现,在这里分享一下我的思路,也希望大家提出一些改进建议。

    二、实现表达式计算的主要思路。

        1、使用的数据结构。

         以前的版本实现表达式计算用的是二叉树数据结构,二叉树有两个子节点,最多支持双目运算符或者带两个参数的函数,可是如果函数的参数很多,就不好处理了,所以当前的版本,用的数据结构是动态数组,实现原理就是先把字符串表达式转换成动态数组,数组中存储运算符、参与运算的数、括号等。这样运算符或者函数的参数个数就不受限制,可以支持更多类型的运算符。

        2、对运算符进行分类。

        对运算符的分类处理是该程序的一个重要思路,运算符虽然有很多,但是可以将运算符归类,针对每一类运算符分别处理,这样核心算法就不会涉及到具体的运算符,只会涉及到运算符的类别。这样以后如果要扩展更多的运算符就会很方便,不需要再修改核心算法的代码,只需要修改运算符集合类就可以了。

         用一个枚举类表示运算符的种类,代码如下:

     /// <summary>
        /// 运算符类型
        /// </summary>
        enum OpeType
        {
            /// <summary>
            /// 该运算因子不是运算符
            /// </summary>
            notOperator,
            /// <summary>
            /// 常数或变量(没有参数的运算符)
            /// </summary>
            noParameter,
            /// <summary>
            /// '+'或'-'
            /// 这两个运算符即可以当正负号使用又可以当加减运算符使用
            /// </summary>
            PlusOrMinus,
            /// <summary>
            /// 参数全在左边的运算符
            /// </summary>
            left,
            /// <summary>
            /// 参数全在右边的运算符
            /// </summary>
            right,
            /// <summary>
            /// 左边和右边都有参数的运算符
            /// </summary>
            bothSides,
            /// <summary>
            /// 左括号
            /// </summary>
            leftParenthesis,
            /// <summary>
            /// 右括号
            /// </summary>
            rightParenthesis,
            /// <summary>
            /// 分隔符,这里指逗号
            /// </summary>
            Separator
        }
    View Code

        3、对表达式的进行合法性检查的思路。

        对表达式的合法性检查,我没有学过编译原理,不懂什么是文法分析、词法分析。这个程序检查表达式的合法性的原理是:针对每一类运算符,分别进行判断,检查其参数的个数,参数是在右边还是在左边等等,主要代码如下:

    #region 第四次处理
                //第四次处理,判断表达式是否合法,并在合适的地方插入乘号
                for (int i = 0; i < valList.Count - 1; i++)
                {
                    #region 当前运算因子是数字
                    if (valList[i].type == ValType.Number)//数字
                    {
                        if (valList[i + 1].type == ValType.Operator)//右边是运算符
                        {
                            switch (valList[i + 1].OpeType)
                            {
                                case OpeType.bothSides://正确
                                    break;
                                case OpeType.left://正确
                                    break;
                                case OpeType.leftParenthesis:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.noParameter:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.PlusOrMinus://正确
                                    break;
                                case OpeType.right:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.rightParenthesis://正确
                                    break;
                                case OpeType.Separator://正确
                                    break;
                            }
                        }
                        else//右边是数字
                        {
                            Insert(opeList.GetOpe("*"), i + 1);
                        }
                    }
                    #endregion
    
                    #region 当前运算因子是运算符
                    if (valList[i].type == ValType.Operator)//运算符
                    {
                        #region 当前运算符右边是运算符
                        if (valList[i + 1].type == ValType.Operator)//右边是运算符
                        {
                            switch (valList[i].OpeType)//左运算符
                            {
                                #region case OpeType.bothSides://左运算符参数信息
                                case OpeType.bothSides://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides:
                                            MakeException(i);
                                            break;
                                        case OpeType.left:
                                            MakeException(i);
                                            break;
                                        case OpeType.leftParenthesis://正确
                                            break;
                                        case OpeType.noParameter://正确
                                            break;
                                        case OpeType.PlusOrMinus:
                                            MakeException(i);
                                            break;
                                        case OpeType.right://正确
                                            break;
                                        case OpeType.rightParenthesis:
                                            MakeException(i);
                                            break;
                                        case OpeType.Separator:
                                            MakeException(i);
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.left://左运算符参数信息
                                case OpeType.left://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides://正确
                                            break;
                                        case OpeType.left://正确
                                            break;
                                        case OpeType.leftParenthesis:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.noParameter:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.PlusOrMinus://正确
                                            break;
                                        case OpeType.right:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.rightParenthesis://正确
                                            break;
                                        case OpeType.Separator: //正确
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.leftParenthesis://左运算符参数信息
                                case OpeType.leftParenthesis://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides:
                                            int pos = i + 1 >= 0 ? i + 1 : i;
                                            MakeException(pos);
                                            break;
                                        case OpeType.left:
                                            pos = i + 1 >= 0 ? i + 1 : i;
                                            MakeException(pos);
                                            break;
                                        case OpeType.leftParenthesis://正确
                                            break;
                                        case OpeType.noParameter://正确
                                            break;
                                        case OpeType.PlusOrMinus://正确
                                            break;
                                        case OpeType.right://正确
                                            break;
                                        case OpeType.rightParenthesis:
                                            pos = i - 1 >= 0 ? i - 1 : i;
                                            MakeException(pos);
                                            break;
                                        case OpeType.Separator:
                                            pos = i - 1 >= 0 ? i - 1 : i;
                                            MakeException(pos);
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.noParameter://左运算符参数信息
                                case OpeType.noParameter://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides://正确
                                            break;
                                        case OpeType.left://正确
                                            break;
                                        case OpeType.leftParenthesis:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.noParameter:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.PlusOrMinus://正确
                                            break;
                                        case OpeType.right:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.rightParenthesis://正确
                                            break;
                                        case OpeType.Separator: //正确
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.PlusOrMinus://左运算符参数信息
                                case OpeType.PlusOrMinus://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides:
                                            MakeException(i);
                                            break;
                                        case OpeType.left:
                                            MakeException(i);
                                            break;
                                        case OpeType.leftParenthesis://正确
                                            break;
                                        case OpeType.noParameter://正确
                                            break;
                                        case OpeType.PlusOrMinus:
                                            MakeException(i);
                                            break;
                                        case OpeType.right://正确
                                            break;
                                        case OpeType.rightParenthesis:
                                            MakeException(i);
                                            break;
                                        case OpeType.Separator:
                                            MakeException(i);
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.right://左运算符参数信息
                                case OpeType.right://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides:
                                            MakeException(i);
                                            break;
                                        case OpeType.left:
                                            MakeException(i);
                                            break;
                                        case OpeType.leftParenthesis://正确
                                            break;
                                        case OpeType.noParameter:
                                            MakeException(i);
                                            break;
                                        case OpeType.PlusOrMinus:
                                            MakeException(i);
                                            break;
                                        case OpeType.right:
                                            MakeException(i);
                                            break;
                                        case OpeType.rightParenthesis:
                                            MakeException(i);
                                            break;
                                        case OpeType.Separator:
                                            MakeException(i);
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.rightParenthesis://左运算符参数信息
                                case OpeType.rightParenthesis://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides://正确
                                            break;
                                        case OpeType.left://正确
                                            break;
                                        case OpeType.leftParenthesis:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.noParameter:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.PlusOrMinus://正确
                                            break;
                                        case OpeType.right:
                                            Insert(opeList.GetOpe("*"), i + 1);
                                            break;
                                        case OpeType.rightParenthesis://正确
                                            break;
                                        case OpeType.Separator://正确
                                            break;
                                    }
                                    break;
                                #endregion
    
                                #region case OpeType.Separator://左运算符参数信息
                                case OpeType.Separator://左运算符参数信息
                                    switch (valList[i + 1].OpeType)//右运算符
                                    {
                                        case OpeType.bothSides:
                                            MakeException(i + 1);
                                            break;
                                        case OpeType.left:
                                            MakeException(i + 1);
                                            break;
                                        case OpeType.leftParenthesis://正确
                                            break;
                                        case OpeType.noParameter://正确
                                            break;
                                        case OpeType.PlusOrMinus://正确
                                            break;
                                        case OpeType.right://正确
                                            break;
                                        case OpeType.rightParenthesis:
                                            MakeException(i);
                                            break;
                                        case OpeType.Separator:
                                            MakeException(i);
                                            break;
                                    }
                                    break;
                                #endregion
    
                            }
                        }
                        #endregion
    
                        #region 当前运算符右边是数字
                        else if (valList[i + 1].type == ValType.Number)//运算符右边是数字
                        {
                            switch (valList[i].OpeType)
                            {
                                case OpeType.bothSides://正确
                                    break;
                                case OpeType.left:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.leftParenthesis://正确
                                    break;
                                case OpeType.noParameter:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.PlusOrMinus://正确
                                    break;
                                case OpeType.right:
                                    MakeException(i);
                                    break;
                                case OpeType.rightParenthesis:
                                    Insert(opeList.GetOpe("*"), i + 1);
                                    break;
                                case OpeType.Separator: //正确
                                    break;
                            }
                        }
                        #endregion
    
                    }
                    #endregion
    
                }
                #endregion
    View Code

    三、下面是表达式计算过程的主要步骤:

    1、将字符串表达式中的数字、运算符、括号、逗号等提取出来,按顺序存储在一个动态数组中。

        原理很简单,就是通过字符串搜索来实现,扫描字符串表达式,依次把运算符取出来放到动态数组中,运算符之间的内容就是参与运算的数了。

        把字符串表达式转换成运算符、括号、逗号和数字的动态数组后,后面将处理这个数组,完成运算。

        部分代码如下:

      #region 将字符串表达式转换成运算因子(数字、常数及运算符)列表
            /// <summary>
            /// 将字符串表达式转换成运算因子列表
            /// </summary>
            /// <param name="str">字符串表达式</param>
            private void ToList(List<CalVal> valList, string str)
            {
                do
                {
                    //字符串中首个运算符的位置
                    int opePos = GetOpePos(str);
    
                    CalNum num = null;
                    CalOpe ope = null;
    
                    if (opePos > 0)//找到运算符且它前面有数字
                    {
                        num = GetNum(ref str, opePos);
                    }
                    else if (opePos == 0)//找到运算符且它在字符串最前面
                    {
                        ope = GetOpe(ref str);
                    }
                    else//没有找到运算符
                    {
                        num = GetNum(ref str);
                    }
    
                    if (num != null)
                    {
                        valList.Add(new CalVal(num));
                    }
    
                    if (ope != null)
                    {
                        valList.Add(new CalVal(ope));
                    }
                } while (str != "");
            }
            #endregion
    
            #region 获取字符串中首个运算符或常数的位置
            /// <summary>
            /// 获取字符串中首个运算符或常数的位置
            /// </summary>
            /// <param name="str">字符串</param>
            /// <returns>值若为-1表示未找到</returns>
            private int GetOpePos(string str)
            {
                CalOpeList opeList = new CalOpeList();
    
                int pos = -1;
                for (int i = 0; i < opeList.count; i++)
                {
                    int k = -1;
    
                    int opeIndex = str.IndexOf(opeList.opeList[i].tag);
    
                    //科学计数法的情况:如果'+'或'-'的前面是'E'
                    if (opeList.opeList[i].opeType == OpeType.PlusOrMinus
                        && opeIndex - 1 >= 0
                        && str.Substring(opeIndex - 1, 1) == "E")
                    {
                        //从'+'或'-'的后面重新查找
                        k = str.Substring(opeIndex + 1).IndexOf(opeList.opeList[i].tag);
    
                        if (k != -1)//如果找到
                        {
                            //计算该运算符的位置
                            k += opeIndex + 1;
                        }
                    }
                    else
                    {
                        k = opeIndex;
                    }
    
                    if (pos == -1)
                    {
                        pos = k;
                    }
                    else if (k >= 0 && k < pos)
                    {
                        pos = k;
                    }
                }
    
                return pos;//值若为-1表示未找到
            }
            #endregion
    
            #region 获得运算符
            /// <summary>
            /// 获得运算符
            /// </summary>
            private CalOpe GetOpe(ref string str)
            {
                CalOpeList opeList = new CalOpeList();
                CalOpe ope = null;
    
                for (int i = 0; i < opeList.count; i++)
                {
                    if (str.IndexOf(opeList.opeList[i].tag) == 0)
                    {
                        ope = opeList.opeList[i];
                        //更新str
                        str = str.Substring(opeList.opeList[i].tag.Length);
                        break;
                    }
                }
    
                return ope;
            }
            #endregion
    
            #region 获取数字
            /// <summary>
            /// 获取数字
            /// </summary>
            private CalNum GetNum(ref string str, int opePos)
            {
                CalNum result = null;
    
                result = new CalNum(str.Substring(0, opePos));
    
                //更新str
                str = str.Substring(opePos);
    
                return result;
            }
    
            /// <summary>
            /// 获取数字
            /// </summary>
            private CalNum GetNum(ref string str)
            {
                CalNum result = null;
    
                result = new CalNum(str);
    
                //更新str
                str = "";
    
                return result;
            }
            #endregion
    View Code

     
    2、优先级的处理。

        优先级的处理是表达式计算过程中的一个关键问题。
        动态数组中的每个元素(运算符、分隔符或数字等)都有一个优先级,对存储表达式的动态数组从前往后扫描,遇到左括号,将运算符的优先级提升,遇到右括号的话,将运算符的优先级降低。这样处理过后,动态数组中的运算符的优先级各不相同,括号中的运算符的优先级就会高于括号外的运算符的优先级。比如括号外的加号的优先级低于括号内的加号的优先级,因为在处理的过程中把括号内的加号的优先级提升了。

    /// <summary>
            /// 优先级处理,提高括号中的算式的运算符的优先级
            /// </summary>
            private void LevelProcess()
            {
                int delLevel = 0;//优先级增量
    
                for (int i = 0; i < valList.Count; i++)
                {
                    if (valList[i].type == ValType.Operator)
                    {
                        //如果是左括号
                        if (valList[i].OpeType == OpeType.leftParenthesis)
                        {
                            delLevel += 1000;
                            continue;
                        }
    
                        //如果是右括号
                        if (valList[i].OpeType == OpeType.rightParenthesis)
                        {
                            delLevel -= 1000;
                            continue;
                        }
    
                        valList[i].level = valList[i].ope.level + delLevel;
                    }
                }
            }
    View Code

     
    3、在计算存储在动态数组中的表达式前,先生成优先级列表,并按优先级从高到低排好序。

     #region 生成优先级列表
            /// <summary>
            /// 生成优先级列表
            /// </summary>
            private void MakeLevelList()
            {
                #region 生成优先级列表,优先级按从高到低存储
                //逐个扫描运算因子,提取优先级列表,并按优先级从高到低存储
                for (int i = 0; i < valList.Count; i++)
                {
                    //如果是运算符
                    if (valList[i].type == ValType.Operator)
                    {
                        //如果是括号或分隔符
                        if (valList[i].OpeType == OpeType.leftParenthesis
                            || valList[i].OpeType == OpeType.rightParenthesis
                            || valList[i].OpeType == OpeType.Separator)
                        {
                            continue;
                        }
                        InsertIntoLevelList(ref levelList, valList[i].level);
                    }
                }
                #endregion
            }
            #endregion
    
    #region 将优先级插入到优先级列表中
            /// <summary>
            /// 将优先级插入到优先级列表中
            /// </summary>
            /// <param name="levelList">优先级列表</param>
            /// <param name="level">要插入的优先级</param>
            private void InsertIntoLevelList(ref List<int> levelList, int level)
            {
                //列表为空的情况
                if (levelList.Count == 0)
                {
                    levelList.Add(level);
                    return;
                }
    
                //该优先级是否已存在
                for (int i = 0; i < levelList.Count; i++)
                {
                    //该优先级已存在
                    if (level == levelList[i])
                    {
                        return;
                    }
                }
    
                int k = 0;
                for (; k < levelList.Count; k++)
                {
                    if (level > levelList[k])
                    {
                        levelList.Insert(k, level);
                        break;
                    }
                }
                if (k >= levelList.Count)
                {
                    levelList.Add(level);
                }
            }
            #endregion
    View Code

    4、遍历优先级列表,按照优先级从高到低,扫描表达式动态数组,先计算优先级高的运算,用计算结果替换掉计算之前的运算符和参与运算的数。当把优先级列表中的优先级都处理完,对表达式的计算也就结束了,这时,表达式动态数组中将只剩下计算结果。

        下面是计算过程的主要代码:

    #region 核心算法,对于当前优先级,扫描运算因子列表并计算
                    if (levelList.Count != 0)//优先级列表不为空
                    {
                        #region 处理当前优先级
                        //对于当前优先级,逐个扫描运算因子,处理具有该优先级的运算
                        for (int i = 0; i < valList.Count; i++)
                        {
                            //找到具有该优先级的运算符
                            if (valList[i].type == ValType.Operator
                                && valList[i].level == levelList[0])//该运算因子的优先级等于当前优先级
                            {
                                bool isSign = false;//Sign为true表示当前运算因子是正负号
                                currentPos = valList[i].primalPos;//记录当前运算因子在列表中的原始位置
    
                                //参数列表
                                List<CalNum> numList = new List<CalNum>();
                                //临时计算结果
                                CalNum num;
    
                                switch (valList[i].OpeType)//i表示该运算因子的位置
                                {
                                    #region case OpeType.PlusOrMinus:
                                    case OpeType.PlusOrMinus:
                                        //若该运算符前面没有运算因子
                                        //或前一个运算因子是运算符,则按正负号计算
                                        if (i == 0 || (i - 1 >= 0 && valList[i - 1].type == ValType.Operator))
                                        {
                                            isSign = true;//是正负号
                                            //获取该运算符的参数
                                            if (i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                                            {
                                                //注意,下面第一句不可省略
                                                numList = new List<CalNum>();
    
                                                numList.Add(valList[i + 1].num);
                                            }
    
                                            //计算
                                            num = CalOpeList.Calculate(valList[i].ope, numList);
                                            //更新运算因子列表
                                            ReplaceVal(num, 2, i);
    
                                            //i无需调整
                                        }
                                        else//若前一个运算因子是操作数,则按加减号计算
                                        {
                                            //获取该运算符的参数
                                            if (valList[i - 1].type == ValType.Number
                                                && i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                                            {
                                                //注意,下面第一句不可省略
                                                numList = new List<CalNum>();
    
                                                numList.Add(valList[i - 1].num);
                                                numList.Add(valList[i + 1].num);
                                            }
    
                                            //计算
                                            num = CalOpeList.Calculate(valList[i].ope, numList);
                                            //更新运算因子列表
                                            ReplaceVal(num, 3, i - 1);
                                            //调整i
                                            i--;
                                        }
                                        break;
                                    #endregion
    
                                    #region case OpeType.bothSides:
                                    case OpeType.bothSides:
                                        //获取该运算符的参数
                                        if (i >= 1 && valList[i - 1].type == ValType.Number
                                            && i + 1 < valList.Count && valList[i + 1].type == ValType.Number)
                                        {
                                            //注意,下面第一句不可省略
                                            numList = new List<CalNum>();
    
                                            numList.Add(valList[i - 1].num);
                                            numList.Add(valList[i + 1].num);
                                        }
    
                                        //计算
                                        num = CalOpeList.Calculate(valList[i].ope, numList);
                                        //更新运算因子列表
                                        ReplaceVal(num, 3, i - 1);
                                        //调整i
                                        i--;
                                        break;
                                    #endregion
    
                                    #region case OpeType.left:
                                    case OpeType.left:
                                        //获取该运算符的参数
                                        if (i >= 1 && valList[i - 1].type == ValType.Number)
                                        {
                                            //注意,下面第一句不可省略
                                            numList = new List<CalNum>();
    
                                            numList.Add(valList[i - 1].num);
                                        }
    
                                        //计算
                                        num = CalOpeList.Calculate(valList[i].ope, numList);
                                        //更新运算因子列表
                                        ReplaceVal(num, 2, i - 1);
                                        //调整i
                                        i--;
                                        break;
                                    #endregion
    
                                    #region case OpeType.noParameter:
                                    case OpeType.noParameter:
                                        //注意,下面第一句不可省略
                                        numList = new List<CalNum>();
    
                                        //计算
                                        num = CalOpeList.Calculate(valList[i].ope, numList);
                                        //更新运算因子列表
                                        ReplaceVal(num, 1, i);
                                        break;
                                    #endregion
    
                                    #region case OpeType.right:
                                    case OpeType.right:
                                        #region 该运算符只有一个参数,且它的右边是常数
                                        if (i + 1 < valList.Count
                                            && valList[i].ParameterNumber == 1
                                            && valList[i + 1].type == ValType.Number)
                                        {
                                            //获取该运算符的参数
                                            //注意,下面第一句不可省略
                                            numList = new List<CalNum>();
                                            numList.Add(valList[i + 1].num);
    
                                            //计算
                                            num = CalOpeList.Calculate(valList[i].ope, numList);
                                            //更新运算因子列表
                                            ReplaceVal(num, 2, i);
                                        }
                                        #endregion
    
                                        #region 该运算符不是只有一个参数,或者它的右边不是常数
                                        else
                                        {
                                            //计算参数个数
                                            int count = 0;
    
                                            int k = i + 1;
                                            //从运算符后面开始检测
                                            //如果是左括号、分隔符或数字,则执行while中语句
                                            while (k < valList.Count
                                                && (valList[k].type == ValType.Number
                                                || valList[k].OpeType == OpeType.Separator
                                                || valList[k].OpeType == OpeType.leftParenthesis))
                                            {
                                                //如果是数字,参数个数加1
                                                if (valList[k].type == ValType.Number)
                                                {
                                                    count++;
                                                }
                                                k++;
                                            }
    
                                            //注意,下面第一句不可省略
                                            numList = new List<CalNum>();
    
                                            //从该运算符后面,逐个扫描,获取该运算符的参数
                                            //j表示已读取的参数个数
                                            //m表示检测位置增量
                                            int m = 0;
                                            for (int j = 0; j < count; )
                                            {
                                                //如果找到数字,存为参数
                                                if (valList[i + j + m + 1].type == ValType.Number)
                                                {
                                                    numList.Add(valList[i + j + m + 1].num);
                                                    j++;
                                                }
                                                //如果是分隔符或左括号,检测位置增量加1,表示跳过该运算因子,继续检测
                                                else if (valList[i + j + m + 1].OpeType == OpeType.Separator
                                                    || valList[i + j + m + 1].OpeType == OpeType.leftParenthesis)
                                                {
                                                    m++;
                                                }
                                            }
    
                                            //计算
                                            num = CalOpeList.Calculate(valList[i].ope, numList);
                                            //更新运算因子列表,count+m+2中的2表示运算符本身和右括号
                                            ReplaceVal(num, count + m + 2, i);
                                        }
                                        #endregion
    
                                        break;
    
                                    #endregion
    
                                }//end switch
    
                                if (!isSign)//如果不是正负号
                                {
                                    break;//退出for循环
                                }
                            }
                        }
                        #endregion
    
                        #region 删除处理完的优先级
                        bool levelExists = false;//是否存在具有该优先级的运算符
                        //逐个扫描运算因子,判断是否仍存在具有该优先级的运算符
                        for (int i = 0; i < valList.Count; i++)
                        {
                            if (levelList[0] == valList[i].level)//存在
                            {
                                levelExists = true;
                            }
                        }
                        if (!levelExists)//该优先级已处理完则删除它
                        {
                            levelList.RemoveAt(0);
                        }
                        #endregion
    
                    }
                    #endregion
    View Code

    四、结束语。

        没有什么高深的思想,我用最笨的办法实现了表达式计算。这个程序中用的最多的算法就是字符串查找,以及遍历数组。

        程序截图:

        

        GitHub地址:https://github.com/0611163/ScientificCalculator.git

        源代码下载:http://pan.baidu.com/s/1jGyV45w

        从博客园下载:博客园下载地址

  • 相关阅读:
    jQuery弹出层插件大全:
    JavaScript数组去重的几种方法
    sql去除重复列(行)
    VS无法启动调试
    .将DayOfWeek转换成中文的几种方式
    关于 uniqueidentifier
    链接服务器
    我的目标:系统架构师
    异常(1)
    Visual C++开发工具与调试技巧整理
  • 原文地址:https://www.cnblogs.com/s0611163/p/3504951.html
Copyright © 2020-2023  润新知