private static Boolean TrySimpleParse(String normalizedExpression, out String strExpression, out SimpleFunctions function) { function = SimpleFunctions.None; strExpression = normalizedExpression; /*************************************************** * NOTE: now it has 2 classified conditions: * 1. sub != origin * 2. sub == orgin ***************************************************/ // 1.sub != origin var subExpression = Helper.GetSubExpression(strExpression); if (subExpression != strExpression) { return(true); } // 2. sub == origin /*************************************************** * NOTE: now it has 3 potential conditions: * 1. started with number * 2. started with left bracket --- [Impossible] * 3. start with string which is function name * * so, actually it has 2 classified conditions: * 1. started with number: will return true to continue with search * 2. started with char: to get the function name & parameter ***************************************************/ // 2.1 started with number if (Regex.IsMatch(strExpression, @"^[0-9]")) // should never started with +/-, since it's normalized { return(true); } // 2.2 started with char var match = Regex.Match(strExpression, @"[([{]"); if (!match.Success || match.Index == 0) { throw new Exception(String.Format("TrySimpleParse Expression: {0}", strExpression)); } // get the simple function name var expression1 = strExpression.Substring(0, match.Index).ToUpper(); var functionName = Enum.GetNames(typeof(SimpleFunctions)).FirstOrDefault(p => p.ToUpper() == expression1); if (functionName == null)// not a simple function { return(false); } function = (SimpleFunctions)Enum.Parse(typeof(SimpleFunctions), functionName); strExpression = strExpression.Substring(functionName.Length + 1, strExpression.Length - functionName.Length - 2); return(true); }
private static Boolean TryComplexParse(String normalizedExpression, out String strExpression, out ComplexFunctions complexFunction) { complexFunction = ComplexFunctions.None; strExpression = normalizedExpression; /*************************************************** * NOTE: now it has 2 classified conditions: * 1. sub != origin * 2. sub == orgin ***************************************************/ // 1.sub != origin var subExpression = Helper.GetSubExpression(strExpression); if (subExpression != strExpression) { return(false); } // 2. sub == origin /*************************************************** * NOTE: now it has 3 potential conditions: * 1. started with number * 2. started with left bracket --- [Impossible] * 3. start with string which is function name * * so, actually it has 2 classified conditions: * 1. started with number * 2. started with char ***************************************************/ // 2.1 started with number if (Regex.IsMatch(strExpression, @"^[0-9]")) { return(false); } // 2.2 started with char var match = Regex.Match(strExpression, @"[([{]"); if (!match.Success) { throw new Exception(String.Format("TryComplexParse Expression: {0}", strExpression)); } // get the complex function name var expression1 = strExpression.Substring(0, match.Index).ToUpper(); var functionName = Enum.GetNames(typeof(ComplexFunctions)).FirstOrDefault(p => p.ToUpper() == expression1); if (functionName == null) // not a complex function { return(false); } complexFunction = (ComplexFunctions)Enum.Parse(typeof(ComplexFunctions), functionName); strExpression = strExpression.Substring(functionName.Length + 1, strExpression.Length - functionName.Length - 2); return(true); }
public override Double Compute() { if (String.IsNullOrWhiteSpace(this.Expression)) { return(Double.NaN); } if (Helper.IsNumericValue(this.Expression)) { return(this.ApplyFunction(Double.Parse(this.Expression))); } var _operatorList = new List <String>(); var _unitList = new List <IComputeUnit>(); try { // prepare int i = 0; while (i < Expression.Length) { var strExpression = Expression.Substring(i); var nextMatch = Regex.Match(strExpression, @"[\+\-*/%([{]"); if (!nextMatch.Success) // must be numeric number { _unitList.Add(new NumericUnit(strExpression)); break; } if (nextMatch.Index == 0) { if (Regex.IsMatch(nextMatch.Value, @"[([{]")) { var subExpression = Helper.GetSubExpression(strExpression); var unit = ExpressionHandler.Parse(subExpression); if (unit == null) { return(Double.NaN); } _unitList.Add(unit); i += subExpression.Length; } else if (Regex.IsMatch(nextMatch.Value, @"[\+\-*/%]")) { Debug.Assert(nextMatch.Index == 0 && nextMatch.Length == 1); _operatorList.Add(strExpression[0].ToString()); i++; } } else { if (Regex.IsMatch(strExpression, @"^[0-9]")) // start with number, it must be a numeric unit { _unitList.Add(new NumericUnit(strExpression.Substring(0, nextMatch.Index))); i += nextMatch.Index; } else // must be a complex unit { var subExpression = Helper.GetSubExpression(strExpression); var unit = ExpressionHandler.Parse(subExpression); if (unit == null) { return(Double.NaN); } _unitList.Add(unit); i += subExpression.Length; } } } // calculate Debug.Assert(_operatorList.Count == _unitList.Count - 1); var operators = new List <String>(); var values = new List <Double>(); Double value = Double.NaN; for (i = 0; i < _operatorList.Count; i++) { if (Double.IsNaN(value)) { value = _unitList[i].Compute(); } if (Double.IsNaN(value)) { return(Double.NaN); } if (_operatorList[i] == "*" || _operatorList[i] == "/" || _operatorList[i] == "%") { if (_operatorList[i] == "*") { value *= _unitList[i + 1].Compute(); } else { var temp = _unitList[i + 1].Compute(); if (temp == 0) { return(Double.NaN); } if (_operatorList[i] == "/") { value /= temp; } else { value %= temp; } } continue; } if (Double.IsNaN(value)) { return(Double.NaN); } if (operators.Any() && operators.Last() == "-") { value *= -1; } values.Add(value); operators.Add(_operatorList[i]); value = Double.NaN; } if (Double.IsNaN(value) && (!_operatorList.Any() || _operatorList.Last() == "+" || _operatorList.Last() == "-")) { value = _unitList.Last().Compute(); } if (!Double.IsNaN(value)) { if (operators.Any() && operators.Last() == "-") { value *= -1; } values.Add(value); } // apply function return(this.ApplyFunction(values.Sum())); } catch { return(Double.NaN); } finally { _operatorList.Clear(); _unitList.Clear(); } }
public static String Normalize(String strExpression) { if (String.IsNullOrWhiteSpace(strExpression)) { return("0"); } var expression = strExpression.TrimStart('+'); // remove prefix '+'; while (Regex.IsMatch(expression, @"^[([{]") && Regex.IsMatch(expression, @"[)\]}]$") && Helper.GetSubExpression(expression) == expression) { expression = expression.Substring(1, expression.Length - 2).TrimStart('+'); // remove unnecessary bounded "()"; } if (String.IsNullOrWhiteSpace(expression)) { return("0"); } if (Helper.IsNumericValue(expression)) { return(expression); } if (expression[0] != '+' && expression[0] != '-') { return(expression); } // ZEHONG: maybe here is redundant, add a prefix "0" is no problem I think////////////////////////// var matchs = Regex.Matches(expression, @"[\+\-*/%\,]").OfType <Match>().ToList(); // '+', '-', '*', '/', '%' , ',' if (matchs.Count >= 2) { var temp = expression.Substring(0, matchs[1].Index); if (Helper.IsNumericValue(temp)) // if expression starts with '+' or '-', add "()" to it. { expression = expression.Insert(matchs[1].Index, ")"); expression = expression.Insert(0, "("); return(expression); } } /////////////////////////////////////////////////////////////////////////////////////////////// return("0" + expression); }