Simplify implementation and remove unsupported test coverage

This commit is contained in:
Dean Herbert 2023-10-24 16:01:32 +09:00
parent 794c3a2473
commit 6865d8894d
No known key found for this signature in database
4 changed files with 36 additions and 115 deletions

View File

@ -397,7 +397,6 @@ namespace osu.Game.Tests.NonVisual.Filtering
[TestCase("Title1[Diff]", new int[] { })]
[TestCase("[diff ]with]", new[] { 4 })]
[TestCase("[diff ]with [[ brackets]]]]", new[] { 4 })]
[TestCase("[diff] another [brackets]", new[] { 4 })]
[TestCase("[Diff in title]", new int[] { })]
[TestCase("[Diff in diff]", new int[] { 6 })]
public void TestDifficultySearch(string query, int[] expectedBeatmapIndexes)

View File

@ -59,13 +59,13 @@ namespace osu.Game.Screens.Select.Carousel
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
match &= !criteria.Title.HasFilter || criteria.Title.Matches(BeatmapInfo.Metadata.Title) ||
criteria.Title.Matches(BeatmapInfo.Metadata.TitleUnicode);
match &= !criteria.DifficultyName.HasFilter || criteria.DifficultyName.Matches(BeatmapInfo.DifficultyName) ||
criteria.DifficultyName.Matches(BeatmapInfo.Metadata.TitleUnicode);
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
if (!match) return false;
match &= criteria.DifficultySearchTerms.All(term => term.Matches(BeatmapInfo.DifficultyName));
if (criteria.SearchTerms.Length > 0)
{
var searchableTerms = BeatmapInfo.GetSearchableTerms();

View File

@ -38,6 +38,7 @@ namespace osu.Game.Screens.Select
public OptionalTextFilter Creator;
public OptionalTextFilter Artist;
public OptionalTextFilter Title;
public OptionalTextFilter DifficultyName;
public OptionalRange<double> UserStarDifficulty = new OptionalRange<double>
{
@ -47,11 +48,6 @@ namespace osu.Game.Screens.Select
public OptionalTextFilter[] SearchTerms = Array.Empty<OptionalTextFilter>();
/// <summary>
/// Search terms that are used for searching difficulty names.
/// </summary>
public OptionalTextFilter[] DifficultySearchTerms = Array.Empty<OptionalTextFilter>();
public RulesetInfo? Ruleset;
public bool AllowConvertedBeatmaps;
@ -69,7 +65,39 @@ namespace osu.Game.Screens.Select
{
searchText = value;
SearchTerms = getTermsFromSearchText(value);
List<OptionalTextFilter> terms = new List<OptionalTextFilter>();
string remainingText = value;
// Match either an open difficulty tag to the end of string,
// or match a closed one with a whitespace after it.
//
// To keep things simple, the closing ']' may be included in the match group,
// and is trimmer post-match.
foreach (Match quotedSegment in Regex.Matches(value, "(^|\\s)\\[(.*)(\\]\\s|$)"))
{
DifficultyName = new OptionalTextFilter
{
SearchTerm = quotedSegment.Groups[2].Value.Trim(']')
};
remainingText = remainingText.Replace(quotedSegment.Value, string.Empty);
}
// First handle quoted segments to ensure we keep inline spaces in exact matches.
foreach (Match quotedSegment in Regex.Matches(value, "(\"[^\"]+\"[!]?)"))
{
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;
@ -78,15 +106,6 @@ namespace osu.Game.Screens.Select
}
}
/// <summary>
/// Extracts the search terms from the provided <see cref="string"/>
/// and stores them in <see cref="DifficultySearchTerms"/>.
/// </summary>
public string DifficultySearchText
{
set => DifficultySearchTerms = getTermsFromSearchText(value);
}
/// <summary>
/// Hashes from the <see cref="BeatmapCollection"/> to filter to.
/// </summary>
@ -94,28 +113,6 @@ 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

@ -21,8 +21,6 @@ namespace osu.Game.Screens.Select
internal static void ApplyQueries(FilterCriteria criteria, string query)
{
criteria.DifficultySearchText = extractDifficultySearchText(ref query);
foreach (Match match in query_syntax_regex.Matches(query))
{
string key = match.Groups["key"].Value.ToLowerInvariant();
@ -36,79 +34,6 @@ namespace osu.Game.Screens.Select
criteria.SearchText = query;
}
/// <summary>
/// Extracts and returns the difficulty search text between square brackets.
/// </summary>
/// <param name="query">The search query. The difficulty search text will be removed from the query.</param>
/// <returns>The difficulty search text (without the square brackets).</returns>
private static string extractDifficultySearchText(ref string query)
{
var openingBracketIndexes = new List<int>();
var closingBracketIndexes = new List<int>();
populateIndexLists(query);
return performExtraction(ref query);
void populateIndexLists(string query)
{
bool currentlyBetweenBrackets = false;
for (int i = 0; i < query.Length; i++)
{
switch (query[i])
{
case '[':
if (!currentlyBetweenBrackets && (i == 0 || query[i - 1] == ' '))
{
currentlyBetweenBrackets = true;
openingBracketIndexes.Add(i + 1);
}
break;
case ']':
if (currentlyBetweenBrackets && (i == query.Length - 1 || query[i + 1] == ' '))
{
currentlyBetweenBrackets = false;
closingBracketIndexes.Add(i);
}
break;
}
}
}
string performExtraction(ref string query)
{
var searchTexts = new List<string>();
string originalQuery = query;
for (int i = 0; i < openingBracketIndexes.Count; i++)
{
int startIndex = openingBracketIndexes[i];
int endIndex = closingBracketIndexes.Count > 0
? closingBracketIndexes[Math.Min(i, closingBracketIndexes.Count - 1)]
: query.Length;
string searchText = originalQuery[startIndex..endIndex];
searchTexts.Add(searchText);
query = query
.Replace($" [{searchText}]", "")
.Replace($"[{searchText}] ", "")
.Replace($"[{searchText}]", "")
.Replace($" [{searchText}] ", " ")
.Replace($" [{searchText}", "")
.Replace($"[{searchText}", "");
}
return string.Join(' ', searchTexts);
}
}
private static bool tryParseKeywordCriteria(FilterCriteria criteria, string key, string value, Operator op)
{
switch (key)