diff --git a/src/app/ModuleBrowser.cpp b/src/app/ModuleBrowser.cpp index fce44177..059db495 100644 --- a/src/app/ModuleBrowser.cpp +++ b/src/app/ModuleBrowser.cpp @@ -48,7 +48,7 @@ static float modelScore(plugin::Model *model, const std::string &search) { // s += " "; // s += tag; // } - float score = string::fuzzyScore(s, search); + float score = string::fuzzyScore(string::lowercase(s), string::lowercase(search)); return score; } diff --git a/src/string.cpp b/src/string.cpp index 4cfe1bc8..b500b61c 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -110,157 +110,12 @@ std::string filenameExtension(const std::string &filename) { return std::string(filename, pos + 1); } - -/* -From https://github.com/forrestthewoods/lib_fts by Forrest Smith -License: - -This software is dual-licensed to the public domain and under the following -license: you are granted a perpetual, irrevocable license to copy, modify, -publish, and distribute this file as you see fit. -*/ -static bool fuzzy_match_recursive(const char *pattern, const char *str, int &outScore, const char *strBegin, uint8_t const *srcMatches, uint8_t *matches, int maxMatches, int nextMatch, int &recursionCount, int recursionLimit) { - // Count recursions - ++recursionCount; - if (recursionCount >= recursionLimit) - return false; - - // Detect end of strings - if (*pattern == '\0' || *str == '\0') - return false; - - // Recursion params - bool recursiveMatch = false; - uint8_t bestRecursiveMatches[256]; - int bestRecursiveScore = 0; - - // Loop through pattern and str looking for a match - bool first_match = true; - while (*pattern != '\0' && *str != '\0') { - - // Found match - if (std::tolower(*pattern) == std::tolower(*str)) { - - // Supplied matches buffer was too short - if (nextMatch >= maxMatches) - return false; - - // "Copy-on-Write" srcMatches into matches - if (first_match && srcMatches) { - std::memcpy(matches, srcMatches, nextMatch); - first_match = false; - } - - // Recursive call that "skips" this match - uint8_t recursiveMatches[256]; - int recursiveScore; - if (fuzzy_match_recursive(pattern, str + 1, recursiveScore, strBegin, matches, recursiveMatches, sizeof(recursiveMatches), nextMatch, recursionCount, recursionLimit)) { - - // Pick best recursive score - if (!recursiveMatch || recursiveScore > bestRecursiveScore) { - std::memcpy(bestRecursiveMatches, recursiveMatches, 256); - bestRecursiveScore = recursiveScore; - } - recursiveMatch = true; - } - - // Advance - matches[nextMatch++] = (uint8_t)(str - strBegin); - ++pattern; - } - ++str; - } - - // Determine if full pattern was matched - bool matched = *pattern == '\0' ? true : false; - - // Calculate score - if (matched) { - const int sequential_bonus = 5; // bonus for adjacent matches - const int separator_bonus = 30; // bonus if match occurs after a separator - const int camel_bonus = 0; // bonus if match is uppercase and prev is lower - const int first_letter_bonus = 15; // bonus if the first letter is matched - - const int leading_letter_penalty = 0; // penalty applied for every letter in str before the first match - const int max_leading_letter_penalty = 0; // maximum penalty for leading letters - const int unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter - - // Iterate str to end - while (*str != '\0') - ++str; - - // Initialize score - outScore = 100; - - // Apply leading letter penalty - int penalty = leading_letter_penalty * matches[0]; - if (penalty < max_leading_letter_penalty) - penalty = max_leading_letter_penalty; - outScore += penalty; - - // Apply unmatched penalty - int unmatched = (int)(str - strBegin) - nextMatch; - outScore += unmatched_letter_penalty * unmatched; - - // Apply ordering bonuses - for (int i = 0; i < nextMatch; ++i) { - uint8_t currIdx = matches[i]; - - if (i > 0) { - uint8_t prevIdx = matches[i - 1]; - - // Sequential - if (currIdx == (prevIdx + 1)) - outScore += sequential_bonus; - } - - // Check for bonuses based on neighbor character value - if (currIdx > 0) { - // Camel case - char neighbor = strBegin[currIdx - 1]; - char curr = strBegin[currIdx]; - if (std::islower(neighbor) && std::isupper(curr)) - outScore += camel_bonus; - - // Separator - bool neighborSeparator = neighbor == '_' || neighbor == ' '; - if (neighborSeparator) - outScore += separator_bonus; - } - else { - // First letter - outScore += first_letter_bonus; - } - } - } - - // Return best result - if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) { - // Recursive score is better than "this" - std::memcpy(matches, bestRecursiveMatches, maxMatches); - outScore = bestRecursiveScore; - return true; - } - else if (matched) { - // "this" score is better than recursive - return true; - } - else { - // no match - return false; - } -} - - float fuzzyScore(const std::string &s, const std::string &query) { - uint8_t matches[256]; - int recursionCount = 0; - int recursionLimit = 10; - int score = 0; - bool match = fuzzy_match_recursive(query.c_str(), s.c_str(), score, s.c_str(), - NULL, matches, sizeof(matches), - 0, recursionCount, recursionLimit); - return match ? score : 0.f; + size_t pos = s.find(query); + if (pos == std::string::npos) + return 0.f; + + return (float) (query.size() + 1) / (s.size() + 1); }