Пример #1
0
        public static double Eval(string text)
        {
            EvalWarningFlags warningFlags = EvalWarningFlags.None;

            return(Eval(text, ref warningFlags));
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }