• 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);

  • 相关阅读:
    cocos2d与cocos2d-X中的draw和update
    poj1673
    hdu2128之BFS
    常用的js效验
    OMCS的语音视频带宽占用
    UML类图详细介绍
    [置顶] 获取激活码,激活myeclipse
    CBO学习----03--选择率(Selectivity)
    notepad++ 文件对比插件
    永远不要在Linux 执行的 10 个最危险的命令
  • 原文地址:https://www.cnblogs.com/daxiongblog/p/13494362.html
Copyright © 2020-2023  润新知