/// <summary>
 /// 将逆波兰式转化为可计算的项
 /// </summary>
 /// <param name="polish">逆波兰式字符串</param>
 /// <returns>可计算项目向量</returns>
 private List<PolishItem> GetPolishItemList(string polish)
 {
     List<PolishItem> resVec = new List<PolishItem>();
     string[] polishItem = polish.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
     foreach (string item in polishItem)
     {
         PolishItem poi = null;
         Regex floatRegEx = new Regex("^(\\d*\\.)?\\d+$");
         // 常数项
         //if (item.All((x) => x >= '0' && x <= '9'))
         if (floatRegEx.IsMatch(item))
         {
             double numitem = Convert.ToDouble(item);
             poi = new PolishItem()
             {
                 Number = numitem,
                 Cluster = null,
                 ItemType = PolishItemType.CONSTANT,
                 Reference = numitem
             };
         }
         // 字符串
         else if (item.StartsWith("\"") && item.EndsWith("\""))
         {
             string trimItem = item.Substring(1, item.Length - 2);
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = trimItem,
                 ItemType = PolishItemType.STRING,
                 Reference = trimItem
             };
         }
         // 变量时
         else if ((item.StartsWith("&") || item.StartsWith("$")) && item.Length > 1)
         {
             object varRef = this.Fetch(item);
             if (varRef is double)
             {
                 poi = new PolishItem()
                 {
                     Number = (double)varRef,
                     Cluster = null,
                     ItemType = PolishItemType.VAR_NUM,
                     Reference = varRef
                 };
             }
             else
             {
                 poi = new PolishItem()
                 {
                     Number = 0.0f,
                     Cluster = Convert.ToString(varRef),
                     ItemType = PolishItemType.VAR_STRING,
                     Reference = varRef
                 };
             }
         }
         else if (item == "+")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_PLUS,
                 Reference = null
             };
         }
         else if (item == "-")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_MINUS,
                 Reference = null
             };
         }
         else if (item == "*")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_MULTI,
                 Reference = null
             };
         }
         else if (item == "/")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_DIV,
                 Reference = null
             };
         }
         else if (item == "!")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_NOT,
                 Reference = null
             };
         }
         else if (item == "&&")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_ANDAND,
                 Reference = null
             };
         }
         else if (item == "||")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_OROR,
                 Reference = null
             };
         }
         else if (item == "<>")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_NOTEQUAL,
                 Reference = null
             };
         }
         else if (item == "==")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_EQUAL,
                 Reference = null
             };
         }
         else if (item == ">")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_BIG,
                 Reference = null
             };
         }
         else if (item == "<")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_SMALL,
                 Reference = null
             };
         }
         else if (item == ">=")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_BIGEQUAL,
                 Reference = null
             };
         }
         else if (item == "<=")
         {
             poi = new PolishItem()
             {
                 Number = 0.0f,
                 Cluster = null,
                 ItemType = PolishItemType.CAL_SMALLEQUAL,
                 Reference = null
             };
         }
         if (poi != null)
         {
             resVec.Add(poi);
         }
     }
     return resVec;
 }
Exemple #2
0
 /// <summary>
 /// 获取两个polish计算项是否可以进行操作
 /// </summary>
 /// <param name="p1">操作数1</param>
 /// <param name="p2">操作数2</param>
 /// <returns>是否可以作为操作符的双目</returns>
 public static bool isOperatable(PolishItem p1, PolishItem p2)
 {
     if (p1.Reference != null && p2.Reference != null && p1.Reference.GetType() == p2.Reference.GetType()) { return true; }
     if (p1.ItemType == PolishItemType.CONSTANT && p2.ItemType == PolishItemType.CONSTANT)     { return true; }
     if (p1.ItemType == PolishItemType.CONSTANT && p2.ItemType == PolishItemType.VAR_NUM)      { return true; }
     if (p1.ItemType == PolishItemType.VAR_NUM && p2.ItemType == PolishItemType.VAR_NUM)       { return true; }
     if (p1.ItemType == PolishItemType.VAR_NUM && p2.ItemType == PolishItemType.CONSTANT)      { return true; }
     if (p1.ItemType == PolishItemType.STRING && p2.ItemType == PolishItemType.STRING)         { return true; }
     if (p1.ItemType == PolishItemType.STRING && p2.ItemType == PolishItemType.VAR_STRING)     { return true; }
     if (p1.ItemType == PolishItemType.VAR_STRING && p2.ItemType == PolishItemType.VAR_STRING) { return true; }
     if (p1.ItemType == PolishItemType.VAR_STRING && p2.ItemType == PolishItemType.STRING)     { return true; }
     return false;
 }
        /// <summary>
        /// 计算表达式
        /// </summary>
        /// <param name="polish">表达式的逆波兰式</param>
        /// <returns>计算结果的值(Double/字符串)</returns>
        public object CalculatePolish(string polish)
        {
            List<PolishItem> calcList = this.GetPolishItemList(polish);
            if (calcList.Count == 0)
            {
                return null;
            }
            Stack<PolishItem> calcStack = new Stack<PolishItem>();
            foreach (PolishItem poi in calcList)
            {
                // 操作数压栈
                if (poi.ItemType < PolishItemType.CAL_PLUS)
                {
                    calcStack.Push(poi);
                    continue;
                }
                // 下面开始是运算符
                if (poi.ItemType == PolishItemType.CAL_NOT && calcStack.Count >= 1)
                {
                    PolishItem peeker = calcStack.Peek();
                    if (peeker.ItemType == PolishItemType.CONSTANT || peeker.ItemType == PolishItemType.VAR_NUM)
                    {
                        calcStack.Pop();
                        double notres = Math.Abs(peeker.Number) < 1e-15 ? 1.0 : 0.0;
                        PolishItem np = new PolishItem()
                        {
                            Number = notres,
                            Reference = notres
                        };
                        calcStack.Push(np);
                        continue;
                    }
                    else if (peeker.ItemType == PolishItemType.STRING || peeker.ItemType == PolishItemType.VAR_STRING)
                    {
                        calcStack.Pop();
                        double notres = peeker.Cluster == "" ? 1.0 : 0.0;

                        PolishItem np = new PolishItem()
                        {
                            Number = notres,
                            Reference = notres
                        };
                        calcStack.Push(np);
                        continue;
                    }
                }
                if (calcStack.Count >= 2)
                {
                    PolishItem operand2 = calcStack.Pop();
                    PolishItem operand1 = calcStack.Pop();
                    if (PolishItem.isOperatable(operand1, operand2) == true)
                    {
                        PolishItem newPoi = null;
                        double tempDouble = 0;
                        string tempString = "";
                        switch (poi.ItemType)
                        {
                            case PolishItemType.CAL_PLUS:
                                if (operand1.Reference is string)
                                {
                                    tempString = (string)operand1.Reference + (string)operand2.Reference;
                                    newPoi = new PolishItem()
                                    {
                                        Cluster = tempString,
                                        Reference = tempString
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = (double)operand1.Reference + (double)operand2.Reference;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_MINUS:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference - (double)operand2.Reference;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    throw new Exception("字符串异常操作:减法");
                                }
                                break;
                            case PolishItemType.CAL_MULTI:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference * (double)operand2.Reference;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    throw new Exception("字符串异常操作:乘法");
                                }
                                break;
                            case PolishItemType.CAL_DIV:
                                if (operand1.Reference is double)
                                {
                                    if (Math.Abs((double)operand2.Reference) < 0)
                                    {
                                        throw new Exception("除零错误");
                                    }
                                    tempDouble = (double)operand1.Reference / (double)operand2.Reference;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    throw new Exception("字符串异常操作:除法");
                                }
                                break;
                            case PolishItemType.CAL_ANDAND:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (Math.Abs((double)operand1.Reference) > 0 && Math.Abs((double)operand2.Reference) > 0) ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    throw new Exception("字符串异常操作:&&");
                                }
                                break;
                            case PolishItemType.CAL_OROR:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (Math.Abs((double)operand1.Reference) > 0 || Math.Abs((double)operand2.Reference) > 0) ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    throw new Exception("字符串异常操作:||");
                                }
                                break;
                            case PolishItemType.CAL_EQUAL:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference == (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = (string)operand1.Reference == (string)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_NOTEQUAL:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference != (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = (string)operand1.Reference != (string)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_BIG:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference > (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) > 0 ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_BIGEQUAL:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference >= (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) >= 0 ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_SMALL:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference < (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) < 0 ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            case PolishItemType.CAL_SMALLEQUAL:
                                if (operand1.Reference is double)
                                {
                                    tempDouble = (double)operand1.Reference <= (double)operand2.Reference ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                else
                                {
                                    tempDouble = String.Compare((string)operand1.Reference, (string)operand2.Reference) <= 0 ? 1 : 0;
                                    newPoi = new PolishItem()
                                    {
                                        Number = tempDouble,
                                        Reference = tempDouble
                                    };
                                    calcStack.Push(newPoi);
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
            if (calcStack.Count != 1)
            {
                throw new Exception("表达式有错误");
            }
            return calcStack.Peek().Reference;
        }