55namespace fuzzy_internal
58 QString::const_iterator str,
60 const QString::const_iterator strBegin,
61 const QString::const_iterator strEnd,
62 const QString::const_iterator patternEnd,
63 uint8_t
const *srcMatches,
89static bool fuzzy_match(
const QString pattern,
const QString str,
int &outScore, uint8_t *matches,
int maxMatches)
91 int recursionCount = 0;
93 auto strIt = str.cbegin();
94 auto patternIt = pattern.cbegin();
95 const auto patternEnd = pattern.cend();
96 const auto strEnd = str.cend();
98 return fuzzy_internal::fuzzy_match_recursive(patternIt, strIt, outScore, strIt, strEnd, patternEnd,
nullptr, matches, maxMatches, 0, recursionCount);
103 int recursionCount = 0;
104 uint8_t matches[256];
105 auto maxMatches =
sizeof(matches);
106 auto strIt = str.cbegin();
107 auto patternIt = pattern.cbegin();
108 const auto patternEnd = pattern.cend();
109 const auto strEnd = str.cend();
111 return fuzzy_internal::fuzzy_match_recursive(patternIt, strIt, outScore, strIt, strEnd, patternEnd,
nullptr, matches, maxMatches, 0, recursionCount, 40);
116 QString::const_iterator str,
118 const QString::const_iterator strBegin,
119 const QString::const_iterator strEnd,
120 const QString::const_iterator patternEnd,
121 const uint8_t *srcMatches,
129 static constexpr int recursionLimit = 10;
131 if (recursionCount >= recursionLimit) {
136 if (pattern == patternEnd || str == strEnd) {
141 bool recursiveMatch =
false;
142 uint8_t bestRecursiveMatches[256];
143 int bestRecursiveScore = 0;
146 bool first_match =
true;
147 while (pattern != patternEnd && str != strEnd) {
149 if (pattern->toLower() == str->toLower()) {
151 if (nextMatch >= maxMatches) {
156 if (first_match && srcMatches) {
157 memcpy(matches, srcMatches, nextMatch);
162 uint8_t recursiveMatches[256];
164 auto strNextChar = std::next(str);
173 sizeof(recursiveMatches),
177 if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
178 memcpy(bestRecursiveMatches, recursiveMatches, 256);
179 bestRecursiveScore = recursiveScore;
181 recursiveMatch =
true;
185 matches[nextMatch++] = (uint8_t)(std::distance(strBegin, str));
192 bool matched = pattern == patternEnd ? true :
false;
196 int sequential_bonus = seqBonus;
197 static constexpr int separator_bonus = 30;
198 static constexpr int camel_bonus = 30;
199 static constexpr int first_letter_bonus = 15;
201 static constexpr int leading_letter_penalty = -5;
202 static constexpr int max_leading_letter_penalty = -15;
203 static constexpr int unmatched_letter_penalty = -1;
206 while (str != strEnd) {
214 int penalty = leading_letter_penalty * matches[0];
215 if (penalty < max_leading_letter_penalty) {
216 penalty = max_leading_letter_penalty;
221 const int unmatched = (int)(std::distance(strBegin, str)) - nextMatch;
222 outScore += unmatched_letter_penalty * unmatched;
225 for (
int i = 0; i < nextMatch; ++i) {
226 uint8_t currIdx = matches[i];
229 uint8_t prevIdx = matches[i - 1];
232 if (currIdx == (prevIdx + 1)) {
233 outScore += sequential_bonus;
240 QChar neighbor = *(strBegin + currIdx - 1);
241 QChar curr = *(strBegin + currIdx);
242 if (neighbor.isLower() && curr.isUpper()) {
243 outScore += camel_bonus;
247 bool neighborSeparator = neighbor == QLatin1Char(
'_') || neighbor == QLatin1Char(
' ');
248 if (neighborSeparator) {
249 outScore += separator_bonus;
253 outScore += first_letter_bonus;
259 if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
261 memcpy(matches, bestRecursiveMatches, maxMatches);
262 outScore = bestRecursiveScore;
264 }
else if (matched) {
static bool fuzzy_match_recursive(QString::const_iterator pattern, QString::const_iterator str, int &outScore, const QString::const_iterator strBegin, const QString::const_iterator strEnd, const QString::const_iterator patternEnd, uint8_t const *srcMatches, uint8_t *newMatches, int maxMatches, int nextMatch, int &recursionCount, int seqBonus=15)