コード例 #1
0
ファイル: FormulaParser.cs プロジェクト: AgentTy/General
        private decimal CalculateSegment(string Formula)
        {
            try
            {
                string[] arr;

                #region Validate Formula
                if (!Validate(Formula))
                {
                    return(0);
                }
                #endregion

                #region Clean Formula

                //Remove whitespace
                Formula = Formula.Replace(" ", "");

                //Check for double variables (AB becomes A*B)
                arr = Formula.Split("/+-*%^0123456789().,".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                while (CheckForDoubleVariables(arr))
                {
                    foreach (string s in arr)
                    {
                        if (s.Replace("()", "").Replace(")", "").Length > 1 && !IsReservedWord(s))
                        {
                            Formula = Formula.Replace(s, s.Insert(1, "*"));
                            arr     = Formula.Split("/+-*%^0123456789().,".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                            break;
                        }
                    }
                }

                //Check for a number in front of a variable (5X becomes 5*X)
                arr = Formula.Split("/+-*%^(),".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (string s in arr)
                {
                    int intNumberIndex = s.LastIndexOfAny("0123456789.".ToCharArray());
                    if (intNumberIndex > -1 && intNumberIndex + 1 < s.Length)
                    {
                        Formula = Formula.Replace(s, s.Insert(intNumberIndex + 1, "*"));
                        arr     = Formula.Split("/+-*%^()".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    }
                }

                #endregion

                #region Solve Functions in Formula

                // abs(x) becomes {abs[x]}
                #region Find Functions
                arr = Formula.Split("()".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < arr.Length; i++)
                {
                    if (IsFunction(CleanFunction(arr[i])))
                    {
                        arr[i] = CleanFunction(arr[i]);
                        int intSkip = 0;
                        int intIndexOfFunctionStart = Formula.IndexOf(arr[i] + "(");
                        Formula = StringFunctions.ReplaceOnce(Formula, arr[i] + "(", "{" + arr[i] + "[");

                        for (int i2 = intIndexOfFunctionStart; i2 < Formula.Length; i2++)
                        {
                            if (Formula[i2] == '(')
                            {
                                intSkip++;
                            }

                            if (Formula[i2] == ')')
                            {
                                intSkip--;
                            }

                            if (Formula[i2] == ')' && intSkip < 0)
                            {
                                Formula = Formula.Remove(i2, 1);
                                Formula = Formula.Insert(i2, "]}");
                                break;
                            }
                        }
                    }
                }
                #endregion

                // {abs[x]} becomes 345 etc..
                arr = Formula.Split("{}".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                while (Formula.Contains("["))
                {
                    foreach (string strSegment in arr)
                    {
                        if (strSegment.Contains("[") && strSegment.Contains("]"))
                        {
                            if (IsFunction(CleanFunction(strSegment)))
                            {
                                Functions.IMathFunction objFunction = GetFunction(CleanFunction(strSegment));
                                Formula = Formula.Replace("{" + strSegment + "}", objFunction.Solve(GetParams(strSegment)).ToString());
                                arr     = Formula.Split("{}".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                            }
                        }
                    }
                }

                #endregion

                #region Insert Constants into Formula
                // Pi becomes 3.14....
                arr = Formula.Split("/+-*%^".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (string s in arr)
                {
                    if (s.Contains("(") && !s.Contains(")"))
                    {
                        s.Replace("(", "");
                    }
                    if (s.Contains(")") && !s.Contains("("))
                    {
                        s.Replace(")", "");
                    }

                    foreach (KeyValuePair <string, object> objReservedWord in _objConstants)
                    {
                        if (objReservedWord.Key.Length > 1)
                        {
                            if (s.ToLower() == objReservedWord.Key.ToLower() || s.ToLower() == objReservedWord.Key.ToLower() + "()")
                            {
                                Formula = Formula.Replace(s, objReservedWord.Value.ToString());
                            }
                        }
                        else
                        {
                            if (s.ToLower() == objReservedWord.Key.ToLower() + "()")
                            {
                                Formula = Formula.Replace(s, objReservedWord.Value.ToString());
                            }
                            else if (s.ToLower() == objReservedWord.Key.ToLower() &&
                                     (
                                         s == objReservedWord.Key.ToLower() ||
                                         !Parameters.Keys.Contains((ParameterKey)Enum.Parse(typeof(ParameterKey), s.ToUpper()))
                                     )
                                     )
                            {
                                Formula = Formula.Replace(s, objReservedWord.Value.ToString());
                            }
                        }
                    }
                }
                #endregion

                #region Insert Variables into Formula
                // A becomes 2 etc...
                arr = Formula.Split("/+-*%^()[]{}".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                foreach (KeyValuePair <ParameterKey, object> de in _objParameters)
                {
                    foreach (string s in arr)
                    {
                        if (s.ToUpper() != de.Key.ToString() && s.ToUpper().EndsWith(de.Key.ToString()))
                        {
                            if (de.Value.GetType() == typeof(decimal[]))
                            {
                                throw new ArgumentException("Cannot do this! (" + s + ")");
                            }
                            else
                            {
                                Formula = Formula.Replace(s, (Convert.ToDecimal(s.Replace(de.Key.ToString(), "")) * SqlConvert.ToDecimal(de.Value)).ToString());
                            }
                        }
                    }
                    Formula = Formula.Replace(de.Key.ToString(), de.Value.ToString());
                    Formula = Formula.Replace(de.Key.ToString().ToLower(), de.Value.ToString());
                }

                //Make sure there are no variables left
                arr = Formula.Split("/+-*%^0123456789().".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                if (arr.Length > 0)
                {
                    string strUnassignedVariables = String.Empty;
                    foreach (string s in arr)
                    {
                        strUnassignedVariables += s + ", ";
                    }
                    strUnassignedVariables = StringFunctions.Shave(strUnassignedVariables, 2);
                    throw new ArithmeticException("Forumla contains variables that are unassigned: " + strUnassignedVariables);
                }
                #endregion

                #region Calculate Parenthetic portions of Formula
                // (4 * 7) becomes 28 etc...
                while (Formula.LastIndexOf("(") > -1)
                {
                    int     lastOpenParenthesisIndex = Formula.LastIndexOf("(");
                    int     firstCloseParenthesisIndexAfterLastOpened = Formula.IndexOf(")", lastOpenParenthesisIndex);
                    decimal result        = ProcessOperation(Formula.Substring(lastOpenParenthesisIndex + 1, firstCloseParenthesisIndexAfterLastOpened - lastOpenParenthesisIndex - 1));
                    bool    AppendAsterix = false;
                    if (lastOpenParenthesisIndex > 0)
                    {
                        if (Formula.Substring(lastOpenParenthesisIndex - 1, 1) != "(" && !OperationOrder.Contains(Formula.Substring(lastOpenParenthesisIndex - 1, 1)))
                        {
                            AppendAsterix = true;
                        }
                    }

                    Formula = Formula.Substring(0, lastOpenParenthesisIndex) + (AppendAsterix ? "*" : "") + result.ToString() + Formula.Substring(firstCloseParenthesisIndexAfterLastOpened + 1);
                }
                #endregion

                _strLastFormulaSimplified = Formula;
                return(ProcessOperation(Formula));
            }
            catch (ArgumentException ex)
            {
                throw ex;
            }
            catch (ArithmeticException ex)
            {
                throw ex;
            }
            //catch (Exception ex)
            //{
            //return Calculate(strOriginalFormula);
            //throw new Exception("Error Occured While Calculating. Check Syntax", ex);
            //}
        }