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