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