1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-13 18:47:27 +08:00

Add ability to search for difficulty names

This commit is contained in:
Pasi4K5 2023-09-25 12:52:49 +02:00
parent 81130eacd1
commit 793d1bf970
3 changed files with 50 additions and 18 deletions

View File

@ -64,6 +64,8 @@ namespace osu.Game.Screens.Select.Carousel
if (!match) return false;
match &= criteria.DifficultySearchTerms.All(term => term.Matches(BeatmapInfo.DifficultyName));
if (criteria.SearchTerms.Length > 0)
{
var searchableTerms = BeatmapInfo.GetSearchableTerms();

View File

@ -46,6 +46,7 @@ namespace osu.Game.Screens.Select
};
public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>();
public OptionalTextFilter[] DifficultySearchTerms = Array.Empty<OptionalTextFilter>();
public RulesetInfo? Ruleset;
public bool AllowConvertedBeatmaps;
@ -64,24 +65,7 @@ namespace osu.Game.Screens.Select
{
searchText = value;
List<OptionalTextFilter> terms = new List<OptionalTextFilter>();
string remainingText = value;
// First handle quoted segments to ensure we keep inline spaces in exact matches.
foreach (Match quotedSegment in Regex.Matches(searchText, "(\"[^\"]+\"[!]?)"))
{
terms.Add(new OptionalTextFilter { SearchTerm = quotedSegment.Value });
remainingText = remainingText.Replace(quotedSegment.Value, string.Empty);
}
// Then handle the rest splitting on any spaces.
terms.AddRange(remainingText.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => new OptionalTextFilter
{
SearchTerm = s
}));
SearchTerms = terms.ToArray();
SearchTerms = getTermsFromSearchText(value);
SearchNumber = null;
@ -90,6 +74,11 @@ namespace osu.Game.Screens.Select
}
}
public string DifficultySearchText
{
set => DifficultySearchTerms = getTermsFromSearchText(value);
}
/// <summary>
/// Hashes from the <see cref="BeatmapCollection"/> to filter to.
/// </summary>
@ -97,6 +86,28 @@ namespace osu.Game.Screens.Select
public IRulesetFilterCriteria? RulesetCriteria { get; set; }
private static OptionalTextFilter[] getTermsFromSearchText(string searchText)
{
List<OptionalTextFilter> terms = new List<OptionalTextFilter>();
string remainingText = searchText;
// First handle quoted segments to ensure we keep inline spaces in exact matches.
foreach (Match quotedSegment in Regex.Matches(searchText, "(\"[^\"]+\"[!]?)"))
{
terms.Add(new OptionalTextFilter { SearchTerm = quotedSegment.Value });
remainingText = remainingText.Replace(quotedSegment.Value, string.Empty);
}
// Then handle the rest splitting on any spaces.
terms.AddRange(remainingText.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(s => new OptionalTextFilter
{
SearchTerm = s
}));
return terms.ToArray();
}
public struct OptionalRange<T> : IEquatable<OptionalRange<T>>
where T : struct
{

View File

@ -19,8 +19,27 @@ namespace osu.Game.Screens.Select
@"\b(?<key>\w+)(?<op>(:|=|(>|<)(:|=)?))(?<value>("".*""[!]?)|(\S*))",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex difficulty_query_syntax_regex = new Regex(
@"(\s|^)((\[(?>\[(?<level>)|[^[\]]+|\](?<-level>))*(?(level)(?!))\](\s|$))|(\[.*))",
RegexOptions.Compiled);
internal static void ApplyQueries(FilterCriteria criteria, string query)
{
foreach (Match match in difficulty_query_syntax_regex.Matches(query))
{
// Trim the first character because it's always '[' (ignoring spaces)
string cleanDifficultyQuery = match.Value.Trim(' ')[1..];
if (cleanDifficultyQuery.EndsWith(']'))
cleanDifficultyQuery = cleanDifficultyQuery[..^1];
criteria.DifficultySearchText = cleanDifficultyQuery;
// Insert whitespace if necessary so that the words before and after the difficulty query aren't joined together.
bool insertWhitespace = match.Value.StartsWith(' ') && match.Value.EndsWith(' ');
query = query.Replace(match.Value, insertWhitespace ? " " : "");
}
foreach (Match match in query_syntax_regex.Matches(query))
{
string key = match.Groups["key"].Value.ToLowerInvariant();