algorithm: function()

in packages/fuzzysort/fuzzysort.js [119:207]


  algorithm: function (searchLowerCodes, prepared, searchLowerCode) {
    var targetLowerCodes = prepared._targetLowerCodes;
    var searchLen = searchLowerCodes.length;
    var targetLen = targetLowerCodes.length;
    var searchI = 0; // where we at
    var targetI = 0; // where you at
    var matchesSimpleLen = 0;

    // very basic fuzzy match; to remove non-matching targets ASAP!
    // walk through target. find sequential matches.
    // if all chars aren't found then exit
    for (;;) {
      var isMatch = searchLowerCode === targetLowerCodes[targetI];
      if (isMatch) {
        matchesSimple[matchesSimpleLen++] = targetI;
        ++searchI;
        if (searchI === searchLen) break;
        searchLowerCode = searchLowerCodes[searchI];
      }
      ++targetI;
      if (targetI >= targetLen) return null; // Failed to find searchI
    }

    var searchI = 0;
    var successStrict = false;
    var matchesStrictLen = 0;

    var nextBeginningIndexes = prepared._nextBeginningIndexes;
    if (nextBeginningIndexes === null)
      nextBeginningIndexes = prepared._nextBeginningIndexes =
        fuzzysort.prepareNextBeginningIndexes(prepared.target);
    var firstPossibleI = (targetI =
      matchesSimple[0] === 0 ? 0 : nextBeginningIndexes[matchesSimple[0] - 1]);

    // Our target string successfully matched all characters in sequence!
    // Let's try a more advanced and strict test to improve the score
    // only count it as a match if it's consecutive or a beginning character!
    if (targetI !== targetLen)
      for (;;) {
        if (targetI >= targetLen) {
          // We failed to find a good spot for this search char, go back to the previous search char and force it forward
          if (searchI <= 0) break; // We failed to push chars forward for a better match

          --searchI;
          var lastMatch = matchesStrict[--matchesStrictLen];
          targetI = nextBeginningIndexes[lastMatch];
        } else {
          var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI];
          if (isMatch) {
            matchesStrict[matchesStrictLen++] = targetI;
            ++searchI;
            if (searchI === searchLen) {
              successStrict = true;
              break;
            }
            ++targetI;
          } else {
            targetI = nextBeginningIndexes[targetI];
          }
        }
      }

    {
      // tally up the score & keep track of matches for highlighting later
      if (successStrict) {
        var matchesBest = matchesStrict;
        var matchesBestLen = matchesStrictLen;
      } else {
        var matchesBest = matchesSimple;
        var matchesBestLen = matchesSimpleLen;
      }
      var score = 0;
      var lastTargetI = -1;
      for (var i = 0; i < searchLen; ++i) {
        var targetI = matchesBest[i];
        // score only goes down if they're not consecutive
        if (lastTargetI !== targetI - 1) score -= targetI;
        lastTargetI = targetI;
      }
      if (!successStrict) score *= 1000;
      score -= targetLen - searchLen;
      prepared.score = score;
      prepared.indexes = new Array(matchesBestLen);
      for (var i = matchesBestLen - 1; i >= 0; --i)
        prepared.indexes[i] = matchesBest[i];

      return prepared;
    }
  },