internal static string AdaptMatchLevelPlural(SearchMatchLevel matchLevel) { switch (matchLevel) { case SearchMatchLevel.DID_YOU_MEAN: return("Did you mean"); case SearchMatchLevel.BACKUP: return("Backup matches"); case SearchMatchLevel.PARTIAL: return("Partial matches"); case SearchMatchLevel.SIMILAR: return("Similar matches"); case SearchMatchLevel.VERY_SIMILAR: return("Most likely matches"); case SearchMatchLevel.EXACT: return("Exact matches"); default: throw new InvalidOperationException("Match level could not be adapted: " + matchLevel); } }
/// <summary> /// Checks how well this tag's attribute matches a string search. /// </summary> /// <param name="input">The string search.</param> /// <returns>How well this tag's attribute matches a string search.</returns> public SearchMatchLevel Matches(string input) { input = StripTag(input.ToLower()); string attribute = StripTag(Attribute.Value.ToLower()); string[] inSplit = input.Split('.'); string[] attrSplit = attribute.Split('.', inSplit.Length); if (inSplit.Length > 1) { if (inSplit.Length > attrSplit.Length) { return(SearchMatchLevel.NONE); } SearchMatchLevel lowest = SearchMatchLevel.EXACT; for (int i = 0; i < inSplit.Length; i++) { lowest = EnumHelper.Min(lowest, BasicCheck(inSplit[i], attrSplit[i])); } return(lowest); } else { return(BasicCheck(input, attribute)); } }
/// <summary> /// Checks how well this event matches a string search. /// </summary> /// <param name="input">The string search.</param> /// <returns>How well this event matches a string search.</returns> public SearchMatchLevel Matches(string input) { input = input.ToLower().Trim(); if (!input.StartsWith("on ")) { input = "on " + input; } if (Regex != null) { if (CachedRegex == null) { CachedRegex = new Regex(Regex.Value, RegexOptions.Compiled | RegexOptions.IgnoreCase); } if (CachedRegex.Matches(input).Count > 0) { return(SearchMatchLevel.EXACT); } } input = input.Substring("on ".Length); SearchMatchLevel tentative = SearchMatchLevel.NONE; foreach (string evnt in Events.Value.Split('\n')) { string evt = evnt.ToLower(); if (evt == input) { return(SearchMatchLevel.EXACT); } else if (evt.StartsWith(input)) { int lengthDiff = evt.Length - input.Length; if (lengthDiff > 0 && lengthDiff <= 9) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.VERY_SIMILAR); } else { tentative = EnumHelper.Max(tentative, SearchMatchLevel.SIMILAR); } } else if (evt.Contains(input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.PARTIAL); } else if (Util.IsTextSimilar(evt, input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.DID_YOU_MEAN); } } if (input.Length > 3 && Triggers.Value.ToLower().Contains(input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.BACKUP); } return(tentative); }
/// <summary> /// Searches meta of the specified type and returns any matches more successful than <see cref="SearchMatchLevel.NONE"/>. /// <para>If <see cref="IDenizenMetaType"/> is provided as the type, searches all meta.</para> /// </summary> /// <typeparam name="T">The type to search for.</typeparam> /// <param name="input">The string search.</param> /// <returns>Any and all matching meta of the specified type.</returns> public IEnumerable <SearchResult <T> > Search <T>(string input) where T : IDenizenMetaType { input = input.ToLower(); foreach (T meta in AllOf <T>()) { SearchMatchLevel match = meta.Matches(input); if (match != SearchMatchLevel.NONE) { yield return(new SearchResult <T>() { Result = meta, MatchLevel = match }); } } }
/// <summary> /// Checks how well this action matches a string search. /// </summary> /// <param name="input">The string search.</param> /// <returns>How well this action matches a string search.</returns> public SearchMatchLevel Matches(string input) { input = input.ToLower().Trim(); if (input.StartsWith("on ")) { input = input.Substring("on ".Length); } SearchMatchLevel tentative = SearchMatchLevel.NONE; foreach (string evnt in Actions.Value.Split('\n')) { string evt = evnt.ToLower(); if (evt == input) { return(SearchMatchLevel.EXACT); } else if (evt.StartsWith(input)) { int lengthDiff = evt.Length - input.Length; if (lengthDiff > 0 && lengthDiff <= 3) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.VERY_SIMILAR); } else { tentative = EnumHelper.Max(tentative, SearchMatchLevel.SIMILAR); } } else if (evt.Contains(input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.PARTIAL); } else if (Util.IsTextSimilar(evt, input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.DID_YOU_MEAN); } } if (input.Length > 3 && Triggers.Value.ToLower().Contains(input)) { tentative = EnumHelper.Max(tentative, SearchMatchLevel.BACKUP); } return(tentative); }
/// <summary> /// Handles a search for Denizen meta. /// </summary> /// <typeparam name="T">The meta type.</typeparam> /// <param name="searchInput">The search input.</param> /// <param name="command">The command that initiated this search.</param> /// <param name="listOnly">Whether to only allow a list of results, rather than replying with exact or only matches.</param> /// <returns>Whether any results were found.</returns> public async Task HandleSearch <T>(string searchInput, BotCommand command, bool listOnly = false) where T : IDenizenMetaType { searchInput = searchInput.ToLower(); if (string.IsNullOrWhiteSpace(searchInput)) { return; } if (searchInput == "all") { string allOf = typeof(T) == typeof(IDenizenMetaType) ? "meta" : (Meta.KnownMetaTypeNames[typeof(T)] + "s"); List <Embed> pages = command.Bot.Meta.AllOf <T>().Paginate((tag) => tag.GetListString()) .Select((page) => new EmbedBuilder().WithColor(Color.Gold).WithTitle("All known " + allOf).WithDescription(page).Build()) .ToList(); await command.ReplyAsync(new DiscordPaginatedMessage(pages)); return; } if (searchInput.StartsWith('\\')) { searchInput = searchInput.Substring(1); } IEnumerable <SearchResult <T> > results = Meta.Search <T>(searchInput).OrderByDescending((x) => x.MatchLevel); SearchResult <T> first = results.FirstOrDefault(); if (first.Result == null) { Type type = typeof(T); string error; if (type == typeof(IDenizenMetaType)) { error = "Nothing was found matching the specified input. :pensive:"; } else { error = "No " + Meta.KnownMetaTypeNames[typeof(T)] + "s were found matching the specified input. :pensive:"; } await command.ReplyAsync(new DiscordEmbedMessage(new EmbedBuilder().WithColor(Color.Red).WithDescription(error).Build())); return; } else if (!listOnly && (first.MatchLevel == SearchMatchLevel.EXACT || results.ElementAtOrDefault(1).Result == null)) { await command.ReplyAsync(new DenizenMetaMessage(first.Result, first.MatchLevel)); return; } else { List <Embed> pages = new List <Embed>(); EmbedBuilder builder = new EmbedBuilder().WithColor(Color.Gold); SearchMatchLevel lastLevel = SearchMatchLevel.NONE; EmbedFieldBuilder field = null; string value = string.Empty; int length = 0; int pageLength = 0; foreach (SearchResult <T> result in results) { if (result.MatchLevel != lastLevel) { if (field != null) { builder.AddField(field.WithValue(value.Substring(0, length - 2))); pageLength += length; value = string.Empty; length = 0; } field = new EmbedFieldBuilder().WithName(MetaCommands.AdaptMatchLevelPlural(result.MatchLevel)); lastLevel = result.MatchLevel; if (pageLength > 1250) { pages.Add(builder.Build()); builder = new EmbedBuilder().WithColor(Color.Gold); } } string next = result.Result.GetListString() + ", "; int newLength = next.Length + length; if (newLength > 1000 || newLength + pageLength > 1500) { builder.AddField(field.WithValue(value.Substring(0, length - 2))); pages.Add(builder.Build()); builder = new EmbedBuilder().WithColor(Color.Gold); field = new EmbedFieldBuilder().WithName(MetaCommands.AdaptMatchLevelPlural(result.MatchLevel) + " [Continued]"); pageLength = 0; value = next; length = next.Length; } else { value += next; length = newLength; } } builder.AddField(field.WithValue(value.Substring(0, length - 2))); pages.Add(builder.Build()); await command.ReplyAsync(new DiscordPaginatedMessage(pages)); return; } }
/// <summary> /// Creates a new message containing information about a Denizen meta type. /// </summary> /// <param name="meta">The meta information.</param> /// <param name="matchLevel">How well the meta matched search input.</param> public DenizenMetaMessage(IDenizenMetaType meta, SearchMatchLevel matchLevel) { Meta = meta; MatchLevel = matchLevel; }