1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-30 06:12:58 +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; if (!match) return false;
match &= criteria.DifficultySearchTerms.All(term => term.Matches(BeatmapInfo.DifficultyName));
if (criteria.SearchTerms.Length > 0) if (criteria.SearchTerms.Length > 0)
{ {
var searchableTerms = BeatmapInfo.GetSearchableTerms(); var searchableTerms = BeatmapInfo.GetSearchableTerms();

View File

@ -46,6 +46,7 @@ namespace osu.Game.Screens.Select
}; };
public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>(); public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>();
public OptionalTextFilter[] DifficultySearchTerms = Array.Empty<OptionalTextFilter>();
public RulesetInfo? Ruleset; public RulesetInfo? Ruleset;
public bool AllowConvertedBeatmaps; public bool AllowConvertedBeatmaps;
@ -64,24 +65,7 @@ namespace osu.Game.Screens.Select
{ {
searchText = value; searchText = value;
List<OptionalTextFilter> terms = new List<OptionalTextFilter>(); SearchTerms = getTermsFromSearchText(value);
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();
SearchNumber = null; SearchNumber = null;
@ -90,6 +74,11 @@ namespace osu.Game.Screens.Select
} }
} }
public string DifficultySearchText
{
set => DifficultySearchTerms = getTermsFromSearchText(value);
}
/// <summary> /// <summary>
/// Hashes from the <see cref="BeatmapCollection"/> to filter to. /// Hashes from the <see cref="BeatmapCollection"/> to filter to.
/// </summary> /// </summary>
@ -97,6 +86,28 @@ namespace osu.Game.Screens.Select
public IRulesetFilterCriteria? RulesetCriteria { get; set; } 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>> public struct OptionalRange<T> : IEquatable<OptionalRange<T>>
where T : struct where T : struct
{ {

View File

@ -19,8 +19,27 @@ namespace osu.Game.Screens.Select
@"\b(?<key>\w+)(?<op>(:|=|(>|<)(:|=)?))(?<value>("".*""[!]?)|(\S*))", @"\b(?<key>\w+)(?<op>(:|=|(>|<)(:|=)?))(?<value>("".*""[!]?)|(\S*))",
RegexOptions.Compiled | RegexOptions.IgnoreCase); 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) 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)) foreach (Match match in query_syntax_regex.Matches(query))
{ {
string key = match.Groups["key"].Value.ToLowerInvariant(); string key = match.Groups["key"].Value.ToLowerInvariant();