From 52615c6f52d1d483afeab31c57fa8f8895db745e Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 2 Jan 2020 08:02:23 +1100 Subject: [PATCH 01/18] WIP variables --- Wox.Infrastructure/StringMatcher.cs | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index deff9ff7b..91ac09f01 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -52,12 +52,12 @@ namespace Wox.Infrastructure var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + + var separatedqueryStrings = queryWithoutCase.Split(' '); + int currentSeparatedQueryStringIndex = 0; + var currentSeparatedQueryString = separatedqueryStrings[currentSeparatedQueryStringIndex]; - int currentQueryToCompareIndex = 0; - var queryToCompareSeparated = queryWithoutCase.Split(' '); - var currentQueryToCompare = queryToCompareSeparated[currentQueryToCompareIndex]; - - var patternIndex = 0; + var queryIndex = 0; var firstMatchIndex = -1; var firstMatchIndexInWord = -1; var lastMatchIndex = 0; @@ -70,14 +70,14 @@ namespace Wox.Infrastructure for (var index = 0; index < fullStringToCompareWithoutCase.Length; index++) { var ch = stringToCompare[index]; - if (fullStringToCompareWithoutCase[index] == currentQueryToCompare[patternIndex]) + if (fullStringToCompareWithoutCase[index] == currentSeparatedQueryString[queryIndex]) { if (firstMatchIndex < 0) { // first matched char will become the start of the compared string firstMatchIndex = index; } - if (patternIndex == 0) + if (queryIndex == 0) { // first letter of current word isFullWordMatched = true; firstMatchIndexInWord = index; @@ -85,12 +85,12 @@ namespace Wox.Infrastructure else if (!isFullWordMatched) { // we want to verify that there is not a better match if this is not a full word // in order to do so we need to verify all previous chars are part of the pattern - int startIndexToVerify = index - patternIndex; + int startIndexToVerify = index - queryIndex; bool allMatch = true; - for (int indexToCheck = 0; indexToCheck < patternIndex; indexToCheck++) + for (int indexToCheck = 0; indexToCheck < queryIndex; indexToCheck++) { if (fullStringToCompareWithoutCase[startIndexToVerify + indexToCheck] != - currentQueryToCompare[indexToCheck]) + currentSeparatedQueryString[indexToCheck]) { allMatch = false; } @@ -99,13 +99,13 @@ namespace Wox.Infrastructure if (allMatch) { // update to this as a full word isFullWordMatched = true; - if (currentQueryToCompareIndex == 0) + if (currentSeparatedQueryStringIndex == 0) { // first word so we need to update start index firstMatchIndex = startIndexToVerify; } indexList.RemoveAll(x => x >= firstMatchIndexInWord); - for (int indexToCheck = 0; indexToCheck < patternIndex; indexToCheck++) + for (int indexToCheck = 0; indexToCheck < queryIndex; indexToCheck++) { // update the index list indexList.Add(startIndexToVerify + indexToCheck); } @@ -115,18 +115,22 @@ namespace Wox.Infrastructure lastMatchIndex = index + 1; indexList.Add(index); + queryIndex++; + // increase the pattern matched index and check if everything was matched - if (++patternIndex == currentQueryToCompare.Length) + if (queryIndex == currentSeparatedQueryString.Length) { - if (++currentQueryToCompareIndex >= queryToCompareSeparated.Length) + currentSeparatedQueryStringIndex++; + + if (currentSeparatedQueryStringIndex >= separatedqueryStrings.Length) { // moved over all the words allMatched = true; break; } // otherwise move to the next word - currentQueryToCompare = queryToCompareSeparated[currentQueryToCompareIndex]; - patternIndex = 0; + currentSeparatedQueryString = separatedqueryStrings[currentSeparatedQueryStringIndex]; + queryIndex = 0; if (!isFullWordMatched) { // if any of the words was not fully matched all are not fully matched allWordsFullyMatched = false; From f6d0738c79636918d141930956ecf4ebdfcbee9f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 2 Jan 2020 08:04:16 +1100 Subject: [PATCH 02/18] debug logging --- Wox.Test/FuzzyMatcherTest.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index b5fe58cac..3091102c7 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -191,6 +191,13 @@ namespace Wox.Test // Act var matchResult = StringMatcher.FuzzySearch(queryString, compareString); + Debug.WriteLine(""); + Debug.WriteLine("###############################################"); + Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionString} ({expectedPrecisionScore})"); + Debug.WriteLine("###############################################"); + Debug.WriteLine(""); + // Assert Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(), $"Query:{queryString}{Environment.NewLine} " + @@ -225,6 +232,13 @@ namespace Wox.Test // Act var matchResult = StringMatcher.FuzzySearch(queryString, compareString); + Debug.WriteLine(""); + Debug.WriteLine("###############################################"); + Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionString} ({expectedPrecisionScore})"); + Debug.WriteLine("###############################################"); + Debug.WriteLine(""); + // Assert Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(), $"Query:{queryString}{Environment.NewLine} " + From 84d6fc2787cdd6ebddbd80febc42e9e1d61e3e77 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 3 Jan 2020 07:58:20 +1100 Subject: [PATCH 03/18] Update variable names Make variables more descriptive of the state they represent --- Wox.Infrastructure/StringMatcher.cs | 128 +++++++++++++--------------- 1 file changed, 59 insertions(+), 69 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 91ac09f01..db84d302e 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -52,100 +52,90 @@ namespace Wox.Infrastructure var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; - - var separatedqueryStrings = queryWithoutCase.Split(' '); - int currentSeparatedQueryStringIndex = 0; - var currentSeparatedQueryString = separatedqueryStrings[currentSeparatedQueryStringIndex]; + + var querySubstrings = queryWithoutCase.Split(' '); + int currentQuerySubstringIndex = 0; + var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; + var currentQuerySubstringCharacterIndex = 0; - var queryIndex = 0; var firstMatchIndex = -1; var firstMatchIndexInWord = -1; var lastMatchIndex = 0; - bool allMatched = false; - bool isFullWordMatched = false; + bool allQuerySubstringsMatched = false; + bool matchFoundInPreviousLoop = false; bool allWordsFullyMatched = true; var indexList = new List(); - for (var index = 0; index < fullStringToCompareWithoutCase.Length; index++) + for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { - var ch = stringToCompare[index]; - if (fullStringToCompareWithoutCase[index] == currentSeparatedQueryString[queryIndex]) + if (fullStringToCompareWithoutCase[compareStringIndex] == currentQuerySubstring[currentQuerySubstringCharacterIndex]) { if (firstMatchIndex < 0) - { // first matched char will become the start of the compared string - firstMatchIndex = index; - } - - if (queryIndex == 0) - { // first letter of current word - isFullWordMatched = true; - firstMatchIndexInWord = index; - } - else if (!isFullWordMatched) - { // we want to verify that there is not a better match if this is not a full word - // in order to do so we need to verify all previous chars are part of the pattern - int startIndexToVerify = index - queryIndex; - bool allMatch = true; - for (int indexToCheck = 0; indexToCheck < queryIndex; indexToCheck++) - { - if (fullStringToCompareWithoutCase[startIndexToVerify + indexToCheck] != - currentSeparatedQueryString[indexToCheck]) - { - allMatch = false; - } - } - - if (allMatch) - { // update to this as a full word - isFullWordMatched = true; - if (currentSeparatedQueryStringIndex == 0) - { // first word so we need to update start index - firstMatchIndex = startIndexToVerify; - } - - indexList.RemoveAll(x => x >= firstMatchIndexInWord); - for (int indexToCheck = 0; indexToCheck < queryIndex; indexToCheck++) - { // update the index list - indexList.Add(startIndexToVerify + indexToCheck); - } - } - } - - lastMatchIndex = index + 1; - indexList.Add(index); - - queryIndex++; - - // increase the pattern matched index and check if everything was matched - if (queryIndex == currentSeparatedQueryString.Length) { - currentSeparatedQueryStringIndex++; + // first matched char will become the start of the compared string + firstMatchIndex = compareStringIndex; + } - if (currentSeparatedQueryStringIndex >= separatedqueryStrings.Length) - { // moved over all the words - allMatched = true; + if (currentQuerySubstringCharacterIndex == 0) + { + // first letter of current word + matchFoundInPreviousLoop = true; + firstMatchIndexInWord = compareStringIndex; + } + else if (!matchFoundInPreviousLoop) + { + // we want to verify that there is not a better match if this is not a full word + // in order to do so we need to verify all previous chars are part of the pattern + var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; + + if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) + { + matchFoundInPreviousLoop = true; + + // if it's the begining character of the first query substring that is matched then we need to update start index + firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; + + indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); + } + } + + lastMatchIndex = compareStringIndex + 1; + indexList.Add(compareStringIndex); + + currentQuerySubstringCharacterIndex++; + + // if finished looping through every character in the substring + if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) + { + currentQuerySubstringIndex++; + + // if all query substrings are matched + if (currentQuerySubstringIndex >= querySubstrings.Length) + { + allQuerySubstringsMatched = true; break; } - // otherwise move to the next word - currentSeparatedQueryString = separatedqueryStrings[currentSeparatedQueryStringIndex]; - queryIndex = 0; - if (!isFullWordMatched) - { // if any of the words was not fully matched all are not fully matched + // otherwise move to the next query substring + currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; + currentQuerySubstringCharacterIndex = 0; + + if (!matchFoundInPreviousLoop) + { + // if any of the words was not fully matched all are not fully matched allWordsFullyMatched = false; } } } else { - isFullWordMatched = false; + matchFoundInPreviousLoop = false; } } - - + // return rendered string if we have a match for every char or all substring without whitespaces matched - if (allMatched) + if (allQuerySubstringsMatched) { // check if all query string was contained in string to compare bool containedFully = lastMatchIndex - firstMatchIndex == queryWithoutCase.Length; From 220dbd7e304ef21e44f5d7c03ec7b01392c2f2eb Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 3 Jan 2020 08:02:02 +1100 Subject: [PATCH 04/18] Move some logic into functions - Move checking if there is a prev compare string char match into function - Move updating of index list when a better match is found for the first substring logic into function --- Wox.Infrastructure/StringMatcher.cs | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index db84d302e..e361c0c18 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -155,6 +155,38 @@ namespace Wox.Infrastructure return new MatchResult { Success = false }; } + private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, + string fullStringToCompareWithoutCase, string currentQuerySubstring) + { + var allMatch = true; + for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++) + { + if (fullStringToCompareWithoutCase[startIndexToVerify + indexToCheck] != + currentQuerySubstring[indexToCheck]) + { + allMatch = false; + } + } + + return allMatch; + } + + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) + { + var updatedList = new List(); + + indexList.RemoveAll(x => x >= firstMatchIndexInWord); + + updatedList.AddRange(indexList); + + for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++) + { + updatedList.Add(startIndexToVerify + indexToCheck); + } + + return updatedList; + } + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool isFullyContained, bool allWordsFullyMatched) { From 42a938b50b6382ba6248a346436f0bbcf99462e6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 6 Jan 2020 19:15:05 +1100 Subject: [PATCH 05/18] Simplify IfElse --- Wox.Infrastructure/StringMatcher.cs | 119 ++++++++++++++-------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index e361c0c18..0b0767f58 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -69,68 +69,67 @@ namespace Wox.Infrastructure for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { - if (fullStringToCompareWithoutCase[compareStringIndex] == currentQuerySubstring[currentQuerySubstringCharacterIndex]) - { - if (firstMatchIndex < 0) - { - // first matched char will become the start of the compared string - firstMatchIndex = compareStringIndex; - } - - if (currentQuerySubstringCharacterIndex == 0) - { - // first letter of current word - matchFoundInPreviousLoop = true; - firstMatchIndexInWord = compareStringIndex; - } - else if (!matchFoundInPreviousLoop) - { - // we want to verify that there is not a better match if this is not a full word - // in order to do so we need to verify all previous chars are part of the pattern - var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; - - if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) - { - matchFoundInPreviousLoop = true; - - // if it's the begining character of the first query substring that is matched then we need to update start index - firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; - - indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); - } - } - - lastMatchIndex = compareStringIndex + 1; - indexList.Add(compareStringIndex); - - currentQuerySubstringCharacterIndex++; - - // if finished looping through every character in the substring - if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) - { - currentQuerySubstringIndex++; - - // if all query substrings are matched - if (currentQuerySubstringIndex >= querySubstrings.Length) - { - allQuerySubstringsMatched = true; - break; - } - - // otherwise move to the next query substring - currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; - currentQuerySubstringCharacterIndex = 0; - - if (!matchFoundInPreviousLoop) - { - // if any of the words was not fully matched all are not fully matched - allWordsFullyMatched = false; - } - } - } - else + if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; + continue; + } + + if (firstMatchIndex < 0) + { + // first matched char will become the start of the compared string + firstMatchIndex = compareStringIndex; + } + + if (currentQuerySubstringCharacterIndex == 0) + { + // first letter of current word + matchFoundInPreviousLoop = true; + firstMatchIndexInWord = compareStringIndex; + } + else if (!matchFoundInPreviousLoop) + { + // we want to verify that there is not a better match if this is not a full word + // in order to do so we need to verify all previous chars are part of the pattern + var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; + + if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) + { + matchFoundInPreviousLoop = true; + + // if it's the begining character of the first query substring that is matched then we need to update start index + firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; + + indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); + } + } + + lastMatchIndex = compareStringIndex + 1; + indexList.Add(compareStringIndex); + + currentQuerySubstringCharacterIndex++; + + // if finished looping through every character in the substring + if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) + { + currentQuerySubstringIndex++; + + // if all query substrings are matched + if (currentQuerySubstringIndex >= querySubstrings.Length) + { + allQuerySubstringsMatched = true; + break; + } + + // otherwise move to the next query substring + currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; + currentQuerySubstringCharacterIndex = 0; + + if (!matchFoundInPreviousLoop) + { + // if any of the words was not fully matched all are not fully matched + allWordsFullyMatched = false; + } } } From e453dceacdb2be2db06c01bfeed505722640fdb8 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 6 Jan 2020 20:51:27 +1100 Subject: [PATCH 06/18] Move condition checking into functions - Moved if statement that checks if all query substrings are matched into a funciton - convert into shorthand expression the if statement that checks if all words are fully matched --- Wox.Infrastructure/StringMatcher.cs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 0b0767f58..2d74c2f12 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -109,34 +109,28 @@ namespace Wox.Infrastructure currentQuerySubstringCharacterIndex++; - // if finished looping through every character in the substring + // if finished looping through every character in the current substring if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) { currentQuerySubstringIndex++; - // if all query substrings are matched - if (currentQuerySubstringIndex >= querySubstrings.Length) - { - allQuerySubstringsMatched = true; + allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + if (allQuerySubstringsMatched) break; - } // otherwise move to the next query substring currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; currentQuerySubstringCharacterIndex = 0; - if (!matchFoundInPreviousLoop) - { - // if any of the words was not fully matched all are not fully matched - allWordsFullyMatched = false; - } + // if any of the substrings was not matched then consider as all are not matched + allWordsFullyMatched = !matchFoundInPreviousLoop ? false : allWordsFullyMatched; } } // return rendered string if we have a match for every char or all substring without whitespaces matched if (allQuerySubstringsMatched) { - // check if all query string was contained in string to compare + // check if all query substrings were contained in the string to compare bool containedFully = lastMatchIndex - firstMatchIndex == queryWithoutCase.Length; var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, containedFully, allWordsFullyMatched); var pinyinScore = ScoreForPinyin(stringToCompare, query); @@ -186,6 +180,11 @@ namespace Wox.Infrastructure return updatedList; } + private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, int querySubstringsLength) + { + return currentQuerySubstringIndex >= querySubstringsLength; + } + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool isFullyContained, bool allWordsFullyMatched) { From 04b0f8b2a4cbfb427a9b8067ebacf11e03204511 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 6 Jan 2020 21:06:41 +1100 Subject: [PATCH 07/18] Remove fuzzy match github repo reference + add logic context in summary 1. Remove the github repo reference as we have mixed in substring matching 2. Added context on how the logic is run --- Wox.Infrastructure/StringMatcher.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 2d74c2f12..d71dddb23 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -41,7 +41,13 @@ namespace Wox.Infrastructure } /// - /// refer to https://github.com/mattyork/fuzzy + /// Current method: + /// Character matching + substring matching; + /// 1. Check query substring's character against full compare string, + /// 2. if matched, loop back to verify the previous character. + /// 3. If previous character also matches, and is the start of the substring, update list. + /// 4. Once the previous character is verified, move on to the next character in the query substring. + /// 5. Consider success and move onto scoring if every char or substring without whitespaces matched /// public static MatchResult FuzzySearch(string query, string stringToCompare, MatchOption opt) { @@ -127,7 +133,7 @@ namespace Wox.Infrastructure } } - // return rendered string if we have a match for every char or all substring without whitespaces matched + // return rendered string if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { // check if all query substrings were contained in the string to compare From 19911d9f1f0d3d5cc9f5d370f46105f93589f162 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 6 Jan 2020 21:19:15 +1100 Subject: [PATCH 08/18] Update comment only --- Wox.Infrastructure/StringMatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index d71dddb23..902490e2a 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -133,7 +133,7 @@ namespace Wox.Infrastructure } } - // return rendered string if every char or substring without whitespaces matched + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { // check if all query substrings were contained in the string to compare From 5040f09f0c149db2be2210241cec10c0aede2f56 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 6 Jan 2020 21:38:07 +1100 Subject: [PATCH 09/18] Update method summary only --- Wox.Infrastructure/StringMatcher.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 902490e2a..cfdb0880a 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -41,13 +41,15 @@ namespace Wox.Infrastructure } /// - /// Current method: + /// Current method: /// Character matching + substring matching; - /// 1. Check query substring's character against full compare string, - /// 2. if matched, loop back to verify the previous character. - /// 3. If previous character also matches, and is the start of the substring, update list. - /// 4. Once the previous character is verified, move on to the next character in the query substring. - /// 5. Consider success and move onto scoring if every char or substring without whitespaces matched + /// 1. Query search string is split into substrings, separator is whitespace. + /// 2. Check each query substring's characters against full compare string, + /// 3. if a character in the substring is matched, loop back to verify the previous character. + /// 4. If previous character also matches, and is the start of the substring, update list. + /// 5. Once the previous character is verified, move on to the next character in the query substring. + /// 6. Move onto the next substring's characters until all substrings are checked. + /// 7. Consider success and move onto scoring if every char or substring without whitespaces matched /// public static MatchResult FuzzySearch(string query, string stringToCompare, MatchOption opt) { From e4b017b3040444f11d6af27b613e56b1acbd9999 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 05:59:47 +1100 Subject: [PATCH 10/18] fix index out of range exception occurs when query contains more than one whitespace eg. 'sql manag' --- Wox.Infrastructure/StringMatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index cfdb0880a..d8c6ae215 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -61,7 +61,7 @@ namespace Wox.Infrastructure var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; - var querySubstrings = queryWithoutCase.Split(' '); + var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; var currentQuerySubstringCharacterIndex = 0; From 13996740e032d8568aebbc64a4e91e9220609b06 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 07:12:34 +1100 Subject: [PATCH 11/18] Add additional test which should pass for regular precision --- Wox.Test/FuzzyMatcherTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 3091102c7..7eb16c8a0 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -214,6 +214,7 @@ namespace Wox.Test [TestCase("sql manag", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("sql", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("sql serv", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql studio", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("mic", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] [TestCase("chr", "Shutdown", (int)StringMatcher.SearchPrecisionScore.Regular, false)] [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", (int)StringMatcher.SearchPrecisionScore.Regular, false)] From dde658a514eb504c0d0aa5ec99ba6e26295869de Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 07:22:00 +1100 Subject: [PATCH 12/18] rename variable state allWordsFullyMatched --- Wox.Infrastructure/StringMatcher.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index d8c6ae215..45fbe5808 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -71,7 +71,7 @@ namespace Wox.Infrastructure var lastMatchIndex = 0; bool allQuerySubstringsMatched = false; bool matchFoundInPreviousLoop = false; - bool allWordsFullyMatched = true; + bool allSubstringsContainedInCompareString = true; var indexList = new List(); @@ -131,7 +131,7 @@ namespace Wox.Infrastructure currentQuerySubstringCharacterIndex = 0; // if any of the substrings was not matched then consider as all are not matched - allWordsFullyMatched = !matchFoundInPreviousLoop ? false : allWordsFullyMatched; + allSubstringsContainedInCompareString = !matchFoundInPreviousLoop ? false : allSubstringsContainedInCompareString; } } @@ -140,7 +140,7 @@ namespace Wox.Infrastructure { // check if all query substrings were contained in the string to compare bool containedFully = lastMatchIndex - firstMatchIndex == queryWithoutCase.Length; - var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, containedFully, allWordsFullyMatched); + var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, containedFully, allSubstringsContainedInCompareString); var pinyinScore = ScoreForPinyin(stringToCompare, query); var result = new MatchResult From 0093838a7535b92f996170e3dc090fd284b0207e Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 07:25:13 +1100 Subject: [PATCH 13/18] fix variable state which failed to represent correctly Failed if query text is 'sql servman'- returns true when should be false - moved it up so evaluation is included in the final substring check --- Wox.Infrastructure/StringMatcher.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 45fbe5808..1868eee6e 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -120,6 +120,9 @@ namespace Wox.Infrastructure // if finished looping through every character in the current substring if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) { + // if any of the substrings was not matched then consider as all are not matched + allSubstringsContainedInCompareString = !matchFoundInPreviousLoop ? false : allSubstringsContainedInCompareString; + currentQuerySubstringIndex++; allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); @@ -129,9 +132,6 @@ namespace Wox.Infrastructure // otherwise move to the next query substring currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; currentQuerySubstringCharacterIndex = 0; - - // if any of the substrings was not matched then consider as all are not matched - allSubstringsContainedInCompareString = !matchFoundInPreviousLoop ? false : allSubstringsContainedInCompareString; } } From 24cc5dbaa0930e4ea6176c99410175745e566c57 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 07:55:02 +1100 Subject: [PATCH 14/18] Add unit tests for checking substrings checking if all substrings contained in compareString --- Wox.Infrastructure/StringMatcher.cs | 8 +++++++- Wox.Test/FuzzyMatcherTest.cs | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 1868eee6e..a5162c281 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -147,7 +147,8 @@ namespace Wox.Infrastructure { Success = true, MatchData = indexList, - RawScore = Math.Max(score, pinyinScore) + RawScore = Math.Max(score, pinyinScore), + AllSubstringsContainedInCompareString = allSubstringsContainedInCompareString }; return result; @@ -288,6 +289,11 @@ namespace Wox.Infrastructure } } + /// + /// Indicates if all query's substrings are contained in the string to compare + /// + public bool AllSubstringsContainedInCompareString { get; set; } + /// /// Matched data to highlight. /// diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 7eb16c8a0..660a8ff96 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -247,5 +247,21 @@ namespace Wox.Test $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + $"Precision Level: {expectedPrecisionString}={expectedPrecisionScore}"); } + + [TestCase("sql servman", MicrosoftSqlServerManagementStudio, false)] + [TestCase("sql serv man", MicrosoftSqlServerManagementStudio, true)] + [TestCase("sql", MicrosoftSqlServerManagementStudio, true)] + [TestCase("sqlserv", MicrosoftSqlServerManagementStudio, false)] + [TestCase("mssms", MicrosoftSqlServerManagementStudio, false)] + [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", false)] + [TestCase("ch r", "Change settings for text-to-speech and for speech recognition (if installed).", true)] + public void WhenGivenQueryShouldEvaluateTrueFalseIfCompareStringContainsAllSubstrings(string queryString, string compareString, bool expectedResult) + { + // When, Given + var matchResult = StringMatcher.FuzzySearch(queryString, compareString).AllSubstringsContainedInCompareString; + + // Should + Assert.AreEqual(matchResult, expectedResult); + } } } \ No newline at end of file From 78a20865350e6994105e1185b496e211d289a49f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 08:04:56 +1100 Subject: [PATCH 15/18] Remove containedFully variable state Not necessary to have and not needed to add another dimension to the scoring --- Wox.Infrastructure/StringMatcher.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index a5162c281..27f99b2a6 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -138,9 +138,7 @@ namespace Wox.Infrastructure // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { - // check if all query substrings were contained in the string to compare - bool containedFully = lastMatchIndex - firstMatchIndex == queryWithoutCase.Length; - var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, containedFully, allSubstringsContainedInCompareString); + var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); var pinyinScore = ScoreForPinyin(stringToCompare, query); var result = new MatchResult @@ -194,8 +192,7 @@ namespace Wox.Infrastructure return currentQuerySubstringIndex >= querySubstringsLength; } - private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, - bool isFullyContained, bool allWordsFullyMatched) + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allWordsFullyMatched) { // A match found near the beginning of a string is scored more than a match found near the end // A match is scored more if the characters in the patterns are closer to each other, @@ -212,11 +209,6 @@ namespace Wox.Infrastructure score += 10; } - if (isFullyContained) - { - score += 20; // honestly I'm not sure what would be a good number here or should it factor the size of the pattern - } - if (allWordsFullyMatched) { score += 20; From b54241a5b27d4802e976f2f1b9571a4c4d6f2d36 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 08:28:27 +1100 Subject: [PATCH 16/18] Update scoring for all substrings contained in compare string --- Wox.Infrastructure/StringMatcher.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 27f99b2a6..45d65549a 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -192,7 +192,7 @@ namespace Wox.Infrastructure return currentQuerySubstringIndex >= querySubstringsLength; } - private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allWordsFullyMatched) + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allSubstringsContainedInCompareString) { // A match found near the beginning of a string is scored more than a match found near the end // A match is scored more if the characters in the patterns are closer to each other, @@ -209,10 +209,8 @@ namespace Wox.Infrastructure score += 10; } - if (allWordsFullyMatched) - { - score += 20; - } + if (allSubstringsContainedInCompareString) + score += 10 * string.Concat(query.Where(c => !char.IsWhiteSpace(c))).Count(); return score; } From 2a49b3899aa9f62af3484ca86055a99f35ded274 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 20:26:26 +1100 Subject: [PATCH 17/18] Update tests Two scoring changes only as a result of substring matching. --- Wox.Test/FuzzyMatcherTest.cs | 80 +++++++++++------------------------- 1 file changed, 24 insertions(+), 56 deletions(-) diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 660a8ff96..1d3d16c95 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -122,50 +122,20 @@ namespace Wox.Test } } - [TestCase] - public void WhenGivenStringsForCalScoreMethodThenShouldReturnCurrentScoring() + [TestCase(Chrome, Chrome, 167)] + [TestCase(Chrome, LastIsChrome, 113)] + [TestCase(Chrome, HelpCureHopeRaiseOnMindEntityChrome, 21)] + [TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 15)] + [TestCase(Chrome, CandyCrushSagaFromKing, 0)] + [TestCase("sql", MicrosoftSqlServerManagementStudio, 56)] + [TestCase("sql manag", MicrosoftSqlServerManagementStudio, 119)]//double spacing intended + public void WhenGivenQueryStringThenShouldReturnCurrentScoring(string queryString, string compareString, int expectedScore) { - // Arrange - string searchTerm = "chrome"; // since this looks for specific results it will always be one case - var searchStrings = new List - { - Chrome,//SCORE: 107 - LastIsChrome,//SCORE: 53 - HelpCureHopeRaiseOnMindEntityChrome,//SCORE: 21 - UninstallOrChangeProgramsOnYourComputer, //SCORE: 15 - CandyCrushSagaFromKing//SCORE: 0 - } - .OrderByDescending(x => x) - .ToList(); + // When, Given + var rawScore = StringMatcher.FuzzySearch(queryString, compareString).RawScore; - // Act - var results = new List(); - foreach (var str in searchStrings) - { - results.Add(new Result - { - Title = str, - Score = StringMatcher.FuzzySearch(searchTerm, str).RawScore - }); - } - - // Assert - VerifyResult(147, Chrome); - VerifyResult(93, LastIsChrome); - VerifyResult(41, HelpCureHopeRaiseOnMindEntityChrome); - VerifyResult(35, UninstallOrChangeProgramsOnYourComputer); - VerifyResult(0, CandyCrushSagaFromKing); - - void VerifyResult(int expectedScore, string expectedTitle) - { - var result = results.FirstOrDefault(x => x.Title == expectedTitle); - if (result == null) - { - Assert.Fail($"Fail to find result: {expectedTitle} in result list"); - } - - Assert.AreEqual(expectedScore, result.Score, $"Expected score for {expectedTitle}: {expectedScore}, Actual: {result.Score}"); - } + // Should + Assert.AreEqual(expectedScore, rawScore, $"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}"); } [TestCase("goo", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] @@ -184,26 +154,25 @@ namespace Wox.Test int expectedPrecisionScore, bool expectedPrecisionResult) { - // Arrange - var expectedPrecisionString = (StringMatcher.SearchPrecisionScore)expectedPrecisionScore; - StringMatcher.UserSettingSearchPrecision = expectedPrecisionScore; // this is why static state is evil... + // When + StringMatcher.UserSettingSearchPrecision = expectedPrecisionScore; - // Act + // Given var matchResult = StringMatcher.FuzzySearch(queryString, compareString); Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionString} ({expectedPrecisionScore})"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore} ({expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); - // Assert + // Should Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(), $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Level: {expectedPrecisionString}={expectedPrecisionScore}"); + $"Precision Level: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore}={expectedPrecisionScore}"); } [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", (int)StringMatcher.SearchPrecisionScore.Regular, false)] @@ -226,26 +195,25 @@ namespace Wox.Test int expectedPrecisionScore, bool expectedPrecisionResult) { - // Arrange - var expectedPrecisionString = (StringMatcher.SearchPrecisionScore)expectedPrecisionScore; - StringMatcher.UserSettingSearchPrecision = expectedPrecisionScore; // this is why static state is evil... + // When + StringMatcher.UserSettingSearchPrecision = expectedPrecisionScore; - // Act + // Given var matchResult = StringMatcher.FuzzySearch(queryString, compareString); Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionString} ({expectedPrecisionScore})"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore} ({expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); - // Assert + // Should Assert.AreEqual(expectedPrecisionResult, matchResult.IsSearchPrecisionScoreMet(), $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Level: {expectedPrecisionString}={expectedPrecisionScore}"); + $"Precision Level: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore}={expectedPrecisionScore}"); } [TestCase("sql servman", MicrosoftSqlServerManagementStudio, false)] From 76727d09bf618ad086b6d2f133b532347819e086 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 7 Jan 2020 22:30:36 +1100 Subject: [PATCH 18/18] Update StringMatcher's UserSettingSearchPrecision property type makes more sense and less conversion to int for actual precision score --- Wox.Infrastructure/StringMatcher.cs | 4 +- Wox.Infrastructure/UserSettings/Settings.cs | 17 +++--- Wox.Test/FuzzyMatcherTest.cs | 61 ++++++++++----------- Wox/App.xaml.cs | 2 +- Wox/ViewModel/SettingWindowViewModel.cs | 2 +- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/Wox.Infrastructure/StringMatcher.cs b/Wox.Infrastructure/StringMatcher.cs index 45d65549a..9c667ced0 100644 --- a/Wox.Infrastructure/StringMatcher.cs +++ b/Wox.Infrastructure/StringMatcher.cs @@ -12,7 +12,7 @@ namespace Wox.Infrastructure { public static MatchOption DefaultMatchOption = new MatchOption(); - public static int UserSettingSearchPrecision { get; set; } + public static SearchPrecisionScore UserSettingSearchPrecision { get; set; } public static bool ShouldUsePinyin { get; set; } @@ -296,7 +296,7 @@ namespace Wox.Infrastructure private bool IsSearchPrecisionScoreMet(int score) { - return score >= UserSettingSearchPrecision; + return score >= (int)UserSettingSearchPrecision; } private int ApplySearchPrecisionFilter(int score) diff --git a/Wox.Infrastructure/UserSettings/Settings.cs b/Wox.Infrastructure/UserSettings/Settings.cs index 5a129832a..b11ec069c 100644 --- a/Wox.Infrastructure/UserSettings/Settings.cs +++ b/Wox.Infrastructure/UserSettings/Settings.cs @@ -45,16 +45,19 @@ namespace Wox.Infrastructure.UserSettings { try { - var precisionScore = (StringMatcher.SearchPrecisionScore)Enum.Parse( - typeof(StringMatcher.SearchPrecisionScore), - value); + var precisionScore = (StringMatcher.SearchPrecisionScore)Enum + .Parse(typeof(StringMatcher.SearchPrecisionScore), value); + QuerySearchPrecision = precisionScore; - StringMatcher.UserSettingSearchPrecision = (int)precisionScore; + StringMatcher.UserSettingSearchPrecision = precisionScore; } - catch (System.Exception e) + catch (ArgumentException e) { - // what do we do here?! - Logger.Log.Exception(nameof(Settings), "Fail to set QuerySearchPrecision", e); + Logger.Log.Exception(nameof(Settings), "Failed to load QuerySearchPrecisionString value from Settings file", e); + + QuerySearchPrecision = StringMatcher.SearchPrecisionScore.Regular; + StringMatcher.UserSettingSearchPrecision = StringMatcher.SearchPrecisionScore.Regular; + throw; } } diff --git a/Wox.Test/FuzzyMatcherTest.cs b/Wox.Test/FuzzyMatcherTest.cs index 1d3d16c95..1a8255987 100644 --- a/Wox.Test/FuzzyMatcherTest.cs +++ b/Wox.Test/FuzzyMatcherTest.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Linq; using NUnit.Framework; using Wox.Infrastructure; -using Wox.Infrastructure.UserSettings; using Wox.Plugin; namespace Wox.Test @@ -138,20 +137,20 @@ namespace Wox.Test Assert.AreEqual(expectedScore, rawScore, $"Expected score for compare string '{compareString}': {expectedScore}, Actual: {rawScore}"); } - [TestCase("goo", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Google Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("chr", "Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.None, true)] - [TestCase("ccs", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Low, true)] - [TestCase("cand", "Candy Crush Saga from King", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("cand", "Help cure hope raise on mind entity Chrome", (int)StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("goo", "Google Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Google Chrome", StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("chr", "Chrome", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.None, true)] + [TestCase("ccs", "Candy Crush Saga from King", StringMatcher.SearchPrecisionScore.Low, true)] + [TestCase("cand", "Candy Crush Saga from King",StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("cand", "Help cure hope raise on mind entity Chrome", StringMatcher.SearchPrecisionScore.Regular, false)] public void WhenGivenDesiredPrecisionThenShouldReturnAllResultsGreaterOrEqual( string queryString, string compareString, - int expectedPrecisionScore, + StringMatcher.SearchPrecisionScore expectedPrecisionScore, bool expectedPrecisionResult) { // When @@ -163,7 +162,7 @@ namespace Wox.Test Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore} ({expectedPrecisionScore})"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int)expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -172,27 +171,27 @@ namespace Wox.Test $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Level: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore}={expectedPrecisionScore}"); + $"Precision Score: {(int)expectedPrecisionScore}"); } - [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("term", "Windows Terminal (Preview)", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql manag", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql serv", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("sql studio", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("mic", MicrosoftSqlServerManagementStudio, (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("chr", "Shutdown", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", (int)StringMatcher.SearchPrecisionScore.Regular, false)] - [TestCase("a test", "This is a test", (int)StringMatcher.SearchPrecisionScore.Regular, true)] - [TestCase("test", "This is a test", (int)StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("exce", "OverLeaf-Latex: An online LaTeX editor", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("term", "Windows Terminal (Preview)", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql s managa", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("sql' s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("sql s manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql manag", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql serv", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("sql studio", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("mic", MicrosoftSqlServerManagementStudio, StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("chr", "Shutdown", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("chr", "Change settings for text-to-speech and for speech recognition (if installed).", StringMatcher.SearchPrecisionScore.Regular, false)] + [TestCase("a test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] + [TestCase("test", "This is a test", StringMatcher.SearchPrecisionScore.Regular, true)] public void WhenGivenQueryShouldReturnResultsContainingAllQuerySubstrings( string queryString, string compareString, - int expectedPrecisionScore, + StringMatcher.SearchPrecisionScore expectedPrecisionScore, bool expectedPrecisionResult) { // When @@ -204,7 +203,7 @@ namespace Wox.Test Debug.WriteLine(""); Debug.WriteLine("###############################################"); Debug.WriteLine($"QueryString: {queryString} CompareString: {compareString}"); - Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore} ({expectedPrecisionScore})"); + Debug.WriteLine($"RAW SCORE: {matchResult.RawScore.ToString()}, PrecisionLevelSetAt: {expectedPrecisionScore} ({(int)expectedPrecisionScore})"); Debug.WriteLine("###############################################"); Debug.WriteLine(""); @@ -213,7 +212,7 @@ namespace Wox.Test $"Query:{queryString}{Environment.NewLine} " + $"Compare:{compareString}{Environment.NewLine}" + $"Raw Score: {matchResult.RawScore}{Environment.NewLine}" + - $"Precision Level: {(StringMatcher.SearchPrecisionScore)expectedPrecisionScore}={expectedPrecisionScore}"); + $"Precision Score: {(int)expectedPrecisionScore}"); } [TestCase("sql servman", MicrosoftSqlServerManagementStudio, false)] diff --git a/Wox/App.xaml.cs b/Wox/App.xaml.cs index aa5426d06..9436df475 100644 --- a/Wox/App.xaml.cs +++ b/Wox/App.xaml.cs @@ -55,7 +55,7 @@ namespace Wox Alphabet.Initialize(_settings); - StringMatcher.UserSettingSearchPrecision = (int)_settings.QuerySearchPrecision; + StringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision; StringMatcher.ShouldUsePinyin = _settings.ShouldUsePinyin; PluginManager.LoadPlugins(_settings.PluginSettings); diff --git a/Wox/ViewModel/SettingWindowViewModel.cs b/Wox/ViewModel/SettingWindowViewModel.cs index 67b8d7af0..19a31be58 100644 --- a/Wox/ViewModel/SettingWindowViewModel.cs +++ b/Wox/ViewModel/SettingWindowViewModel.cs @@ -73,7 +73,7 @@ namespace Wox.ViewModel public List QuerySearchPrecisionStrings { get - { + { var precisionStrings = new List(); var enumList = Enum.GetValues(typeof(StringMatcher.SearchPrecisionScore)).Cast().ToList();