Created
April 2, 2018 19:13
-
-
Save eivindingebrigtsen/8738d6de1699d66a02cf99b6b3865ded to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* LiquidMetal, version: 1.3.0 (2014-08-19) | |
* | |
* A mimetic poly-alloy of Quicksilver's scoring algorithm, essentially | |
* LiquidMetal. | |
* | |
* For usage and examples, visit: | |
* http://github.com/rmm5t/liquidmetal | |
* | |
* Licensed under the MIT: | |
* http://www.opensource.org/licenses/mit-license.php | |
* | |
* Copyright (c) 2009-2017, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org) | |
*/ | |
(function(global) { | |
var SCORE_NO_MATCH = 0.0; | |
var SCORE_MATCH = 1.0; | |
var SCORE_TRAILING = 0.8; | |
var SCORE_TRAILING_BUT_STARTED = 0.9; | |
var SCORE_BUFFER = 0.85; | |
var WORD_SEPARATORS = " \t_-"; | |
var LiquidMetal = { | |
lastScore: null, | |
lastScoreArray: null, | |
score: function(string, abbrev) { | |
// short circuits | |
if (abbrev.length === 0) return SCORE_TRAILING; | |
if (abbrev.length > string.length) return SCORE_NO_MATCH; | |
// match & score all | |
var allScores = []; | |
var search = string.toLowerCase(); | |
abbrev = abbrev.toLowerCase(); | |
this._scoreAll(string, search, abbrev, -1, 0, [], allScores); | |
// complete miss | |
if (allScores.length == 0) return 0; | |
// sum per-character scores into overall scores, | |
// selecting the maximum score | |
var maxScore = 0.0, maxArray = []; | |
for (var i = 0; i < allScores.length; i++) { | |
var scores = allScores[i]; | |
var scoreSum = 0.0; | |
for (var j = 0; j < string.length; j++) { scoreSum += scores[j]; } | |
if (scoreSum > maxScore) { | |
maxScore = scoreSum; | |
maxArray = scores; | |
} | |
} | |
// normalize max score by string length | |
// s. t. the perfect match score = 1 | |
maxScore /= string.length; | |
// record maximum score & score array, return | |
this.lastScore = maxScore; | |
this.lastScoreArray = maxArray; | |
return maxScore; | |
}, | |
_scoreAll: function(string, search, abbrev, searchIndex, abbrIndex, scores, allScores) { | |
// save completed match scores at end of search | |
if (abbrIndex == abbrev.length) { | |
// add trailing score for the remainder of the match | |
var started = (search.charAt(0) == abbrev.charAt(0)); | |
var trailScore = started ? SCORE_TRAILING_BUT_STARTED : SCORE_TRAILING; | |
fillArray(scores, trailScore, scores.length, string.length); | |
// save score clone (since reference is persisted in scores) | |
allScores.push(scores.slice(0)); | |
return; | |
} | |
// consume current char to match | |
var c = abbrev.charAt(abbrIndex); | |
abbrIndex++; | |
// cancel match if a character is missing | |
var index = search.indexOf(c, searchIndex); | |
if (index == -1) return; | |
// match all instances of the abbreviaton char | |
var scoreIndex = searchIndex; // score section to update | |
while ((index = search.indexOf(c, searchIndex+1)) != -1) { | |
// score this match according to context | |
if (isNewWord(string, index)) { | |
scores[index-1] = 1; | |
fillArray(scores, SCORE_BUFFER, scoreIndex+1, index-1); | |
} | |
else if (isUpperCase(string, index)) { | |
fillArray(scores, SCORE_BUFFER, scoreIndex+1, index); | |
} | |
else { | |
fillArray(scores, SCORE_NO_MATCH, scoreIndex+1, index); | |
} | |
scores[index] = SCORE_MATCH; | |
// consume matched string and continue search | |
searchIndex = index; | |
this._scoreAll(string, search, abbrev, searchIndex, abbrIndex, scores, allScores); | |
} | |
} | |
}; | |
function isUpperCase(string, index) { | |
var c = string.charAt(index); | |
return ("A" <= c && c <= "Z"); | |
} | |
function isNewWord(string, index) { | |
var c = string.charAt(index-1); | |
return (WORD_SEPARATORS.indexOf(c) != -1); | |
} | |
function fillArray(array, value, from, to) { | |
for (var i = from; i < to; i++) { array[i] = value; } | |
return array; | |
} | |
// Export as AMD... | |
if (typeof define === 'function' && define.amd) { | |
define(function () { return LiquidMetal; }); | |
} | |
// ...or as a node module | |
else if (typeof module !== 'undefined' && module.exports) { | |
module.exports = LiquidMetal; | |
} | |
else { | |
global.LiquidMetal = LiquidMetal; | |
} | |
})(typeof window !== 'undefined' ? window : this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment