public void Basic_TplRegex_Test() { TplRegex tplReg = new TplRegex(new ParsableString("field2 \"Regex Here\"")); Assert.IsTrue(tplReg.TargetField == "field2", "First Field capture failed: " + tplReg.TargetField); Assert.IsTrue(tplReg.Rex.ToString() == "Regex Here", "First Regex capture failed: " + tplReg.Rex); tplReg = new TplRegex(new ParsableString(" \"Regex Here\" ")); Assert.IsTrue(tplReg.TargetField == "_raw", "Second Field capture failed: " + tplReg.TargetField); Assert.IsTrue(tplReg.Rex.ToString() == "Regex Here", "Second Regex capture failed: " + tplReg.Rex); }
public static TplFunction Create(string query, out IReadOnlyList <LogMessage> errors) { var grammar = new TplGrammar(); var tplLangData = new LanguageData(grammar); var tplParser = new Parser(tplLangData); var parseTree = tplParser.Parse(query); if (parseTree.HasErrors()) { errors = parseTree.ParserMessages; return(null); } else { errors = new List <LogMessage>(0); var functionNodes = parseTree.Root.ChildNodes.Select(node => node.ChildNodes); TplFunction rootFunction = null; foreach (var funcNode in functionNodes) { TplFunction currentFunction; var funcName = funcNode[0].FindToken().Text; switch (funcName.ToLower()) { case "between": currentFunction = new TplBetween() { TargetField = GetOptionalVariable(funcNode[1]), StartValue = funcNode[2].FindToken().ValueString, EndValue = funcNode[3].FindToken().ValueString, Inclusive = GetSwitchValue(funcNode[4], "inclusive"), }; break; case "dedup": currentFunction = new TplDedup() { TargetFields = GetOptionalVariableList(funcNode[1]), Mode = GetSwitchValue(funcNode[2], "all") ? TplDedup.DedupMode.All : TplDedup.DedupMode.Consecutive, }; break; case "delete": { var fields = GetOptionalVariableList(funcNode[1]); if (fields.Count < 1) { throw funcNode[0].GetException("At least one field name is required in Delete function"); } currentFunction = new TplDelete() { SelectedFields = fields }; } break; case "eval": var expTree = GetAsExpressionTree(funcNode[3], null); currentFunction = new TplEval(funcNode[3].GetAsExpressionTree(null)) { NewFieldName = funcNode[1].FindTokenAndGetValue <string>(), }; break; case "first": currentFunction = new TplFirst() { First = funcNode[1].FindTokenAndGetValue <int>(), }; break; case "last": currentFunction = new TplLast() { Last = funcNode[1].FindTokenAndGetValue <int>(), }; break; case "group": currentFunction = new TplGroup() { TargetField = GetOptionalVariable(funcNode[1]), StartRegex = funcNode[2].FindToken().GetTokenAsRegex(), EndRegex = funcNode[3].FindToken().GetTokenAsRegex(), }; break; case "kv": currentFunction = new TplKeyValue() { TargetFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD), KeyValueRegex = GetTokenAsRegex(funcNode[2].FindToken()) }; break; case "rex": ValidateArgumentList(funcNode[3], "passthru"); currentFunction = new TplRegex() { TargetField = GetOptionalVariable(funcNode[1]), Rex = GetTokenAsRegex(funcNode[2].FindToken()), PassThru = GetNamedArgumentValue(funcNode[3], "passthru", false), }; break; case "select": currentFunction = new TplSelect() { SelectedFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD) }; break; case "sort": currentFunction = new TplSort( funcNode[1].ChildNodes .Select(sortNode => new TplSortField(sortNode.ChildNodes[0].FindToken().ValueString, (sortNode.ChildNodes.Count > 1 ? (sortNode.ChildNodes[1].FindToken().ValueString == "desc") : false))) .ToList() ); break; case "stats": { ValidateArgumentList(funcNode[3], "count", "sum", "avg"); if (!funcNode[3].ChildNodes.Any()) { throw funcNode[0].GetException("Expected 1 or more of the following arguments: 'count', 'sum', or 'avg' in 'stats' function"); } List <string> byFields; if (funcNode[2].ChildNodes.Any()) // if the keyword 'by' is present, look for by fields { byFields = GetOptionalVariableList(funcNode[2].ChildNodes[1]); if (!byFields.Any()) { throw funcNode[2].GetException("Expected 1 or more variables in 'stats' function after 'by'"); } } else { byFields = new List <string>(0); } currentFunction = new TplStats() { TargetFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD), ByFields = byFields, Avg = GetNamedArgumentValue(funcNode[3], "avg", false), Count = GetNamedArgumentValue(funcNode[3], "count", false), Sum = GetNamedArgumentValue(funcNode[3], "sum", false), }; } break; case "where": currentFunction = new TplWhere(funcNode[1].GetAsExpressionTree(null)); break; case "tolower": case "toupper": ValidateArgumentList(funcNode[2], "rex", "group"); { var rex = GetNamedArgumentValue <Regex>(funcNode[2], "rex", null); var group = GetNamedArgumentValue <string>(funcNode[2], "group", null); if (rex == null && group != null) { throw new InvalidOperationException($"Invalid argument 'group' in {funcName}. A group cannot be specified unless the 'rex' argument is also specified"); } else if (rex != null && group != null && !rex.GetNamedCaptureGroupNames().Contains(group)) { throw new InvalidOperationException($"Invalid value '{group}' for 'group' argument in {funcName}. The capture group does not exist in the specified regex"); } currentFunction = new TplChangeCase() { TargetFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD), ToUpper = funcName.ToLower() == "toupper", TargetGroup = group, MatchingRegex = rex }; } break; case "replace": ValidateArgumentList(funcNode[4], "as", "rex", "group", "case"); { var rex = new TplReplace() { TargetFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD), Replace = funcNode[3].FindTokenAndGetValue <string>(), AsField = GetNamedArgumentValue <string>(funcNode[4], "as", null), TargetGroup = GetNamedArgumentValue <string>(funcNode[4], "group", null), CaseSensitive = GetNamedArgumentValue <bool>(funcNode[4], "case", false), RegexMode = GetNamedArgumentValue <bool>(funcNode[4], "rex", false), }; rex.Find = funcNode[2].FindTokenAndGetValue <string>(); currentFunction = rex; } break; case "splice": { ValidateArgumentList(funcNode[3], "as"); var targetField = GetOptionalVariable(funcNode[1]); currentFunction = new TplSplice(funcNode[2].FindTokenAndGetValue <string>()) { TargetField = targetField, AsField = GetNamedArgumentValue(funcNode[3], "as", targetField) }; } break; case "concat": { var concatValues = funcNode[3].ChildNodes .Select(value => value.FindToken()) .Select(t => new ConcatValue(t.ValueString, t.Text[0] == '$')) .ToList(); currentFunction = new TplStringConcat(concatValues, funcNode[1].FindToken().ValueString); } break; case "padleft": case "padright": { ValidateArgumentList(funcNode[3], "char"); currentFunction = new TplStringPad() { TargetFields = GetOptionalVariableList(funcNode[1], TplResult.DEFAULT_FIELD), TotalLength = funcNode[2].FindTokenAndGetValue <int>(), PaddingChar = GetNamedArgumentValue <char>(funcNode[3], "char", ' '), PadRight = funcName == "padright", }; } break; case "substr": { ValidateArgumentList(funcNode[4], "as"); var target = GetOptionalVariable(funcNode[1]); currentFunction = new TplSubstring() { TargetField = target, StartIndex = funcNode[2].FindTokenAndGetValue <int>(), MaxLength = funcNode[3].FindTokenAndGetValue <int>(-1), AsField = GetNamedArgumentValue <string>(funcNode[4], "as", target), }; } break; case "split": { currentFunction = new TplSplit() { TargetField = GetOptionalVariable(funcNode[1]), SplitOn = funcNode[2].FindTokenAndGetValue <string>(), }; } break; case "readlines": { ValidateArgumentList(funcNode[2], "recurse"); currentFunction = new TplReadLines() { FilePath = funcNode[1].FindTokenAndGetValue <string>(), Recurse = GetNamedArgumentValue(funcNode[2], "recurse", false), }; } break; default: throw new InvalidOperationException($"Invalid function name '{funcName}'"); } if (rootFunction == null) { rootFunction = currentFunction; } else { rootFunction.AddToPipeline(currentFunction); } } return(rootFunction); } }