C# 使用棧結構實現 邏輯代碼腳本的解析

   /// <summary>
    /// 代碼解釋器
    /// </summary>
    public class CodeStructureInterpreter
    {
        /// <summary>
        /// 數組開始括號 默認‘[’
        /// </summary>
        public char StartArrBrace { get; set; } = '[';

        /// <summary>
        /// 邏輯結束括號 默認‘]’
        /// </summary>
        public char EndArrBrace { get; set; } = ']';
        private Stack<int> _codeStack;
        private string _code;
        private static Dictionary<char, string> LogicDic = new Dictionary<char, string>()
        {
            {'', "AND"},
            {'', "OR"},
            {'', "NOT"}
        };


        public CodeStructureInterpreter(string code)
        {
            _code = code;
        }

        /// <summary>
        /// 提取
        /// </summary>
        public Interlingua DoExctract(out string msg)
        {
            msg = "";
            if (string.IsNullOrWhiteSpace(_code))
            {
                msg = "輸入條件爲空!";
                return null;
            }
            var codeArea = DoExtractCodeArea('{', '}', ref msg, true);

            return new Interlingua();
        }
        /// <summary>
        /// 提取代碼塊
        /// </summary>
        /// <returns></returns>
        public CodeArea DoExtractCodeArea(char startBrace, char endBrace, ref string msg, bool hasLogic = false)
        {
            var len = _code.Length;
            if (len == 0 || len == 1)
            {
                msg = "輸入條件長度錯誤!";
                return null;
            }
            Stack<WordBrace> areaStack = new Stack<WordBrace>();
            //父節點和序號
            Dictionary<string, int> sortDic = new Dictionary<string, int>();
            var i = 0;
            List<CodeArea> tempList = new List<CodeArea>();
            while (i < len)
            {
                var depth = areaStack.Count;
                var code = _code[i];
                if (code == '"')//字符串跳過
                {
                    var str = GetCodeSting(_code, i, out int end, ref msg);
                    if (end == 0)
                    {
                        msg = string.IsNullOrWhiteSpace(msg) ? "字符串處理失敗" : msg;
                        return null;
                    }
                    i = end + 1;
                    continue;
                }
                if (code == startBrace)
                {

                    var parentKey = "0";//父節點唯一標識
                    if (depth > 0)
                    {
                        var parent = areaStack.Peek();
                        parentKey = parent.Key;

                    }
                    if (sortDic.ContainsKey(parentKey))
                    {
                        sortDic[parentKey]++;
                    }
                    else
                    {
                        sortDic.Add(parentKey, 1);
                    }
                    var key = sortDic[parentKey].ToString();
                    key = $"{parentKey}_{key}";//當前節點唯一標識
                    areaStack.Push(new WordBrace(code, key, i, depth, sortDic[parentKey])
                    {
                        CodeAreaObj = new CodeArea() { Depth = depth, Key = key, ParentKey = parentKey }
                    });
                }
                else if (code == endBrace && depth > 0)
                {
                    if (depth == 0)
                    {
                        msg = $"{code} 附近語法錯誤,位置{i}。";
                        return null;
                    }
                    var start = areaStack.Pop();
                    var startIndex = start.Index + 1;
                    start.CodeAreaObj.Express = string.Join("", _code.Skip(startIndex).Take(i - startIndex));
                    tempList.Add(start.CodeAreaObj);

                    if (sortDic.ContainsKey(start.Key))
                    {
                        //重置排序
                        sortDic[start.Key] = 0;
                    }
                }
                else if (hasLogic && LogicDic.ContainsKey(code))
                {
                    if (depth == 0)
                    {
                        msg = $"{code} 附近語法錯誤,不匹配的邏輯符號,位置{i}。";
                        return null;
                    }
                    var temp = areaStack.Peek();
                    temp.CodeAreaObj.LogicOp.Add(LogicDic[code]);
                }
                i++;
            }
            if (areaStack.Count > 0)
            {
                var next = areaStack.Pop();
                msg = $"語法錯誤,沒有關閉的表達式“{startBrace}”。位置{next.Index}";
                return null;
            }

            foreach (var codeArea in tempList)
            {
                Console.WriteLine($"key:{codeArea.Key},depth:{codeArea.Depth},logicOp:{string.Join(";", codeArea.LogicOp)},express:{codeArea.Express}");
            }

            var result = GetAreaTree("0_1", tempList, ref msg);
            if (!string.IsNullOrWhiteSpace(msg))
            {
                return null;
            }
            return result;
        }

        /// <summary>
        /// 獲取字符串並返回結束位置
        /// </summary>
        /// <param name="start">起始位置</param>
        /// <param name="end">返回結束位置</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public string GetCodeSting(string code, int start, out int end, ref string msg)
        {
            char brace = '"';
            char escape = '\\';
            string result = "";
            bool inEscape = false;
            end = 0;
            var len = code.Length;
            Stack<int> strStack = new Stack<int>();
            strStack.Push(start);
            for (int i = start + 1; i < len; i++)
            {
                if (inEscape)
                {
                    if (code[i] != brace && code[i] != escape)
                    {
                        msg = $"無法識別的轉義符號{code[i]},位置:{i}";
                        return null;
                    }
                    inEscape = false;
                    continue;
                }
                if (code[i] == escape)
                {
                    inEscape = true;
                    continue;
                }
                if (code[i] == brace)
                {
                    strStack.Pop();
                    end = i;
                    var startIndex = start + 1;
                    result = string.Join("", code.Skip(startIndex).Take(i - startIndex));
                    break;
                }

            }
            if (strStack.Count > 0)
            {
                var i = strStack.Pop();
                msg = $"未能識別的符號 {code[i]} ,位置:{i}";
                return null;
            }
            return result.Trim();
        }
        /// <summary>
        /// 構造代碼塊樹狀結構
        /// </summary>
        /// <param name="key"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public CodeArea GetAreaTree(string key, List<CodeArea> list, ref string msg)
        {
            var result = list.Find(f => f.Key == key);
            if(result.LogicOp==null || result.LogicOp.Count==0)
                result.ExpressOpRules = GetFilterRulesByExpress(result.Express, ref msg);

            if (list.Exists(e => e.ParentKey == result.Key))
            {
                foreach (var codeArea in list.FindAll(f => f.ParentKey == result.Key))
                {
                    if (result.ChildrenAreas == null) result.ChildrenAreas = new List<CodeArea>();
                    result.ChildrenAreas.Add(GetAreaTree(codeArea.Key, list, ref msg));
                }

            }
            return result;
        }
        /// <summary>
        /// 轉換成能篩選的表達式
        /// </summary>
        /// <returns></returns>
        private List<FilterRules> GetFilterRulesByExpress(string express, ref string msg)
        {
            if (string.IsNullOrWhiteSpace(express))
            {
                msg += "";
                return null;
            }
            var dataStart = express.IndexOf('"');
            var data = GetCodeSting(express, dataStart, out int end, ref msg);
            if (string.IsNullOrWhiteSpace(data) && end == 0)
            {
                msg += $"{express} 附近有語法錯誤";
                return null;
            }
            var other = express.Remove(dataStart, end- dataStart+1);
            if (!other.Contains(":"))
            {
                msg += $"{express} 附近有語法錯誤,沒有找到 ‘:’ 號";
                return null;
            }
            var ohterArr = other.Split(':');
            if (ohterArr.Length != 2)
            {
                msg += $"{express} 附近有語法錯誤,請檢查是否規範";
                return null;
            }
            var field = ohterArr[0];
            List<FilterRules> list = new List<FilterRules>();
            list.Add(new FilterRules() { Field = field, Fdata = data });
            return list;
        }
       
        //private FiltersOp GetFilterGroup(CodeArea codeArea)
        //{
        //    var result = new FiltersOp() { FilterOps = new List<FiltersOp>() };
        //    if (codeArea.LogicOp != null)
        //        result.GroupOp = string.Join(",", codeArea.LogicOp);
        //    if (codeArea.HasChildren)
        //    {
        //        foreach (var childrenArea in codeArea.ChildrenAreas)
        //        {
        //            result.FilterOps.Add(GetFilterGroup(childrenArea));
        //        }
        //    }
        //    else
        //    {
        //        result.OpRules = codeArea.ExpressOpRules;
        //        Console.WriteLine(string.Join(",", codeArea.ExpressOpRules.Select(s => s.Field)) );
        //        Console.WriteLine(string.Join(",", codeArea.ExpressOpRules.Select(s => s.Fdata)) );
        //    }
        //    return result;
        //}
    }
    /// <summary>
    /// 代碼塊
    /// </summary>
    public class CodeArea
    {
        /// <summary>
        /// 父級的序號
        /// </summary>
        public string ParentKey { get; set; }
        /// <summary>
        /// 當前Key "1_1"
        /// </summary>
        public string Key { get; set; }

        /// <summary>
        /// 深度
        /// </summary>
        public int Depth { get; set; }
        /// <summary>
        /// 序號
        /// </summary>
        public int Sort { get; set; }

        /// <summary>
        /// 表達式
        /// </summary>
        public string Express { get; set; }
        /// <summary>
        /// 關聯符
        /// </summary>
        public List<string> LogicOp { get; set; } = new List<string>();
        /// <summary>
        /// 子代碼塊
        /// </summary>
        public List<CodeArea> ChildrenAreas { get; set; }
        /// <summary>
        /// 是否還有子代碼塊
        /// </summary>
        public bool HasChildren => ChildrenAreas?.Count > 0;
        /// <summary>
        ///表達式處理後的系統可識別的表達式
        /// </summary>
        public List<FilterRules> ExpressOpRules { get; set; }

    }
    /// <summary>
    /// 入棧 起始終止符 信息
    /// </summary>
    public class WordBrace
    {
        public WordBrace(char symble, string key, int index, int depth, int sort)
        {
            Symble = symble;
            Index = index;
            Depth = depth;
            Sort = sort;
            Key = key;

        }
        public char Symble { get; set; }
        public int Index { get; set; }
        public int Depth { get; set; }
        public int Sort { get; set; }
        public string Key { get; set; }
        public CodeArea CodeAreaObj { get; set; }
    }

    /// <summary>
    /// 過濾條件類
    /// </summary>
    public class FiltersOp
    {
        /// <summary>
        /// 操作符
        /// </summary>
        public string GroupOp { get; set; }
        /// <summary>
        /// 過濾規則,和字段
        /// </summary>
        public List<FilterRules> OpRules { get; set; }
        /// <summary>
        /// 下級過濾條件
        /// </summary>
        public List<FiltersOp> FilterOps { get; set; }
    }
    /// <summary>
    /// 過濾規則
    /// </summary>
    public class FilterRules
    {
        /// <summary>
        /// 字段
        /// </summary>
        public string Field { get; set; }
        /// <summary>
        /// 操作符
        /// </summary>
        public string Op { get; set; }
        /// <summary>
        ////// </summary>
        public string Fdata { get; set; }
    }

調用結果:

 CodeStructureInterpreter codeInterpreter = new CodeStructureInterpreter("{{{{字段:\"空}}}}}\\\"\\\"\"} 和 {字段:\"問\"}和{字段:\"a\"}} 或 {字段:$in[\"旗\",\"空\"]}} 非 {{{字段:\"空\"} 和 {字段:\"眼\"}} 或 {{字段:\"旗\"} 和 {字段:\"問\"}}}}");
            codeInterpreter.DoExctract(out var msg);
            Console.WriteLine(msg);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章