public static double Eval(string text) { EvalWarningFlags warningFlags = EvalWarningFlags.None; return(Eval(text, ref warningFlags)); }
public static double Eval(string text, ref EvalWarningFlags warningFlags) { text = text.Trim().Replace(" ", ""); string[] specialStringList = { "{", "}", "[", "]" }; foreach (string x in specialStringList) { if (text.Contains(x)) { throw new InvalidOperationException("Contains unsupport char:" + x + " input:" + text); } } MatchCollection matches; //bool isWrongFmtDetect; //string[,] fmtReplacePair = { { "--", "+" },{ "-+", "-" },{ "+-", "-" },{ "--", "+" },{ "++", "+" },{ "+-", "-" } }; //do //{ // isWrongFmtDetect = false; // for (int i = 0; i < fmtReplacePair.GetLength(0); i++) // { // if (text.Contains(fmtReplacePair[i,0])) // { // isWrongFmtDetect = true; // text = text.Replace(fmtReplacePair[i, 0], fmtReplacePair[i, 1]); // } // } //} while (isWrongFmtDetect); int rootIdx = 0; List <double> listValue = new List <double>(); List <string> listLevel = new List <string>(); //Step1. replace numbers //matches = Regex.Matches(text, "exp|e"); //var matchList = matches.Cast<Match>().Where(x => x.Value.ToLower().Equals("e")).ToList<Match>(); ////matches = Regex.Matches(text, "((0x|0b|-|\\+)?[\\da-fA-F\\.]+b?|pi|conste)");//\(([^\(\)]*)\) //matches = Regex.Matches(text, "(0x)[\\da-fA-F]+|(0b)[01]+|[01]+b|pi|conste|(-|\\+)?[\\d.]+");//\(([^\(\)]*)\) //matchList.AddRange(matches.Cast<Match>().ToList()); //matches = Regex.Matches(text, "[\\d.]");//\(([^\(\)]*)\) //for (int i= matches.Count-1;i>=0;i--) //{ // char peekPre = (char)0, peekPrePre = (char)0, peekPost = (char)0; // if (matches[i].Index > 0) peekPre = text[matches[i].Index - 1]; // if (matches[i].Index > 1) peekPrePre = text[matches[i].Index - 2]; // if (matches[i].Index + 1 < text.Length) peekPost = text[matches[i].Index + 1]; // if (peekPre == '-' && (peekPrePre != )) // { // text = text.Insert(matches[i].Index-1, "+"); // continue; // } // if (matches[i].Value == "0" && (peekPost == 'x' || peekPost == 'b')) continue; // text = text.Insert(matches[i].Index, "+"); //} matches = Regex.Matches(text, "(0x)[\\da-fA-F]+|(0b)[01]+|[01]+b|pi|conste|[\\d.]+|exp|e");//\(([^\(\)]*)\) var matchList = matches.Cast <Match>().Where(x => !x.Value.ToLower().Equals("exp")).ToList <Match>(); string textNoNum = ReplaceWithIndex(text, matchList, true, listValue.Count, "[", "]"); foreach (Match m in matchList) { double val = StrToValue(m.Value); if (Double.IsNaN(val)) { throw new Exception("ERROR [" + m.Value + "] can not convert to number...."); } listValue.Add(val); } //Step2. Detect parentheses pairs string textLevel = textNoNum; Console.WriteLine(textLevel); int level = 0; do { matches = Regex.Matches(textLevel, "\\(([^\\(\\)]*)\\)"); textLevel = ReplaceWithIndex(textLevel, matches, true, listLevel.Count, "{", "}"); foreach (Match m in matches) { listLevel.Add(m.Value.Substring(1, m.Value.Length - 2)); } Console.WriteLine(level + ": " + textLevel); level++; } while (matches.Count != 0); rootIdx = listLevel.Count; listLevel.Add(textLevel); Console.WriteLine("Levelv0 (root:" + rootIdx + "):"); for (int i = 0; i < listLevel.Count; i++) { Console.WriteLine(i + ": " + listLevel[i]); } //Step3. Detect the supported operators string patternItem = "[\\[\\{]\\d+[\\]\\}]";//\\[\\d+\\] string[] patternOneSideOpList = new string[] { "log|exp" + "|[a]?cos[h]?|[a]?tan[h]?|[a]?sin[h]?" + "|sqrt|int", "-" }; for (int o = 0; o < patternOneSideOpList.Length; o++) { string patternOneSideOp = patternOneSideOpList[o]; for (int l = 0; l < listLevel.Count; l++) { //matches = Regex.Matches(listLevel[l], patternItem); //if (matches.Count < 2) // continue; matches = Regex.Matches(listLevel[l], patternOneSideOp); if (matches.Count == 0) { continue; } matches = Regex.Matches(listLevel[l], "(" + patternOneSideOp + ")" + patternItem); if (matches.Count == 0 || (matches.Count == 1 && matches[0].Index == 0)) { continue; } string textTmp = ReplaceWithIndex(listLevel[l], matches, true, listLevel.Count, "{", "}"); listLevel[l] = textTmp; foreach (Match m in matches) { listLevel.Add(m.Value); } l--; } string[] patternBaseList = new string[] { "(\\*|\\/|pow|%|>>|<<|\\^|\\||\\&)+(\\+|-)?" + patternItem, "[\\+\\-]+" + patternItem }; string[] patternBaseListPre = new string[] { "", "[\\+\\-]?" }; for (int p = 0; p < patternBaseList.Length; p++) { string patternBase = patternBaseList[p]; string patternPre = patternBaseListPre[p]; for (int l = 0; l < listLevel.Count; l++) { matches = Regex.Matches(listLevel[l], patternItem); if (matches.Count <= 2) { continue; } matches = Regex.Matches(listLevel[l], patternPre + patternItem + "(" + patternBase + ")+"); if (matches.Count == 1 && matches[0].Value.Equals(listLevel[l])) { matches = Regex.Matches(listLevel[l], patternBase); PrintMatches(matches, listLevel[l]); if (matches.Count > 1) { string valEnd = matches[matches.Count - 1].Value; listLevel.Add(listLevel[l].Replace(valEnd, "")); listLevel[l] = "{" + (listLevel.Count - 1) + "}" + valEnd; Console.WriteLine(p + "-" + l + " " + listLevel[l]); } } else { string textTmp = ReplaceWithIndex(listLevel[l], matches, true, listLevel.Count, "{", "}"); listLevel[l] = textTmp; foreach (Match m in matches) { listLevel.Add(m.Value); } } } } } double result = double.NaN; result = GetValue(listLevel[rootIdx], patternItem, listValue, listLevel, ref warningFlags)[0]; Console.WriteLine("Value:"); for (int i = 0; i < listValue.Count; i++) { Console.WriteLine(i + ": " + listValue[i]); } Console.WriteLine("Levelv1 (root:" + rootIdx + "):"); for (int i = 0; i < listLevel.Count; i++) { Console.WriteLine(i + ": " + listLevel[i]); } Console.WriteLine("Result : " + result); //PrintMatches(matches, text); return(result); }
public static List <double> GetValue(string textLevel, string patternItem, List <double> listValue, List <string> listLevel, ref EvalWarningFlags warningFlags) { MatchCollection matches; matches = Regex.Matches(textLevel, patternItem); double baseValue = 1; List <double> valueList0 = null, valueList1 = null; if (matches.Count >= 1) { if (matches[0].Value.Equals(textLevel)) { int valIdx; if (int.TryParse(textLevel.Substring(1, textLevel.Length - 2), out valIdx)) { if (textLevel.StartsWith("{")) { return(GetValue(listLevel[valIdx], patternItem, listValue, listLevel, ref warningFlags)); } else { return new List <double> { listValue[valIdx] } }; } else { throw new Exception("ERROR Next idx@ : " + textLevel); } } valueList0 = GetValue(matches[0].Value, patternItem, listValue, listLevel, ref warningFlags); if (matches[0].Index != 0) { string op0 = textLevel.Substring(0, matches[0].Index); op0 = FixAddAndSub(op0); while (op0.Length != 0 && (op0[0] == '-' || op0[0] == '+')) { if (op0[0] == '-') { baseValue *= -1; } op0 = op0.Substring(1, op0.Length - 1); } valueList0[0] *= baseValue; if (op0.Length != 0) { double value0Tmp; double value0 = valueList0[0]; switch (op0) { case "-": value0Tmp = value0 * -1; break; case "log": value0Tmp = Math.Log(value0); break; case "exp": value0Tmp = Math.Exp(value0); break; case "sqrt": value0Tmp = Math.Sqrt(value0); break; case "cos": value0Tmp = Math.Cos(value0); break; case "cosh": value0Tmp = Math.Cosh(value0); break; case "acos": value0Tmp = Math.Acos(value0); break; case "sin": value0Tmp = Math.Sin(value0); break; case "sinh": value0Tmp = Math.Sinh(value0); break; case "asin": value0Tmp = Math.Asin(value0); break; case "tan": value0Tmp = Math.Tan(value0); break; case "tanh": value0Tmp = Math.Tanh(value0); break; case "atan": value0Tmp = Math.Atan(value0); break; case "rnd": { var rand = new Random(); value0Tmp = value0 * rand.NextDouble(); } break; case "int": if (!(value0 >= -9223372036854775808.0 && // -2^63 value0 < 9223372036854775808.0)) // 2^63 { throw new OverflowException($"{value0} to int64"); } value0Tmp = (long)value0; break; default: throw new Exception("ERROR unknown op0@ : " + textLevel + " op:" + op0); } if (double.IsNaN(value0Tmp)) { throw new ArgumentOutOfRangeException("", $"{op0}({value0})"); } valueList0 = new List <double> { value0Tmp }; } } if (matches.Count == 1) { if (matches[0].Index + matches[0].Length != textLevel.Length) { throw new Exception("ERROR unknown status@ : " + textLevel + " matchcount:" + matches.Count); } return(valueList0); } } if (matches.Count == 2) { if (matches[matches.Count - 1].Index + matches[matches.Count - 1].Length != textLevel.Length) { throw new Exception("ERROR unknown status@ : " + textLevel + " matchcount:" + matches.Count); } int opStart1 = 0, opEnd1 = 0; opStart1 = matches[matches.Count - 2].Index + matches[matches.Count - 2].Length; opEnd1 = matches[matches.Count - 1].Index; valueList1 = GetValue(matches[1].Value, patternItem, listValue, listLevel, ref warningFlags); string op1 = ""; if (opEnd1 == opStart1) { op1 = "+"; } else if (opEnd1 > opStart1) { op1 = textLevel.Substring(opStart1, opEnd1 - opStart1); op1 = FixAddAndSub(op1); } double value0, value1, valueResult; value0 = valueList0[0]; value1 = valueList1[0]; valueResult = double.NaN; if (op1.Length != 0) { switch (op1) { case "+": valueResult = value0 + value1; break; case "-": valueResult = value0 - value1; break; case "*": valueResult = value0 * value1; break; case "/": if (value1 == 0) { throw new DivideByZeroException("ERROR div by zero@ : " + textLevel + " value1:" + matches[1].Value); } valueResult = value0 / value1; break; case "pow": valueResult = Math.Pow(value0, value1); break; case "%": valueResult = (long)value0 % (long)value1; break; case "^": valueResult = (long)value0 ^ (long)value1; break; case "|": valueResult = (long)value0 | (long)value1; break; case "&": valueResult = (long)value0 & (long)value1; break; case "<<": if (value1 > Int32.MaxValue) { throw new OverflowException($"{value1} to int"); } else if ((double)((int)value0) != value0 || (double)((int)value1) != value1) { warningFlags |= EvalWarningFlags.DoubleToInt; } valueResult = value1 >= 0 ? (long)value0 << (int)value1 : (long)value0 >> (int)(-value1); break; case ">>": if (value1 > Int32.MaxValue) { throw new OverflowException($"{value1} to int"); } else if ((double)((int)value0) != value0 || (double)((int)value1) != value1) { warningFlags |= EvalWarningFlags.DoubleToInt; } valueResult = value1 >= 0 ? (long)value0 >> (int)value1 : (long)value0 << (int)(-value1); break; } } else { throw new Exception("ERROR unknown op1@ : " + textLevel + " opStart:" + opStart1 + " opEnd:" + opEnd1); } return(new List <double> { valueResult }); } else { throw new Exception("ERROR too much matches@ : " + textLevel + " matchcount:" + matches.Count); } throw new Exception("ERROR unknown status@ : " + textLevel + " matchcount:" + matches.Count); }