Permalink
Browse files

Update LiquidMetal comparison to 1.2.1 from 0.1

  • Loading branch information...
Joshaven Potter
Joshaven Potter committed Sep 28, 2013
1 parent da864fa commit ba7240ae5f8ddfed87d1e9dee8b0af7fdc7bafea
Showing with 70 additions and 37 deletions.
  1. +70 −37 tests/comparisons/liquidmetal.js
@@ -1,5 +1,5 @@
-/*
- * LiquidMetal, version: 0.1 (2009-02-05)
+/**
+ * LiquidMetal, version: 1.2.1 (2012-04-21)
*
* A mimetic poly-alloy of Quicksilver's scoring algorithm, essentially
* LiquidMetal.
@@ -10,62 +10,97 @@
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
- * Copyright (c) 2009, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
+ * Copyright (c) 2009-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
-var LiquidMetal = function() {
+var LiquidMetal = (function() {
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_-";
return {
- score: function(string, abbreviation) {
- // Short circuits
- if (abbreviation.length == 0) return SCORE_TRAILING;
- if (abbreviation.length > string.length) return SCORE_NO_MATCH;
+ lastScore: null,
+ lastScoreArray: null,
- var scores = this.buildScoreArray(string, abbreviation);
+ score: function(string, abbrev) {
+ // short circuits
+ if (abbrev.length === 0) return SCORE_TRAILING;
+ if (abbrev.length > string.length) return SCORE_NO_MATCH;
- var sum = 0.0;
- for (var i in scores) {
- sum += scores[i];
+ // 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;
+ }
}
- return (sum / scores.length);
+ // 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;
},
- buildScoreArray: function(string, abbreviation) {
- var scores = new Array(string.length);
- var lower = string.toLowerCase();
- var chars = abbreviation.toLowerCase().split("");
+ _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;
+ }
- var lastIndex = -1;
- var started = false;
- for (var i in chars) {
- var c = chars[i];
- var index = lower.indexOf(c, lastIndex+1);
- if (index < 0) return fillArray(scores, SCORE_NO_MATCH);
- if (index == 0) started = true;
+ // 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, lastIndex+1, index-1);
+ fillArray(scores, SCORE_BUFFER, scoreIndex+1, index-1);
}
else if (isUpperCase(string, index)) {
- fillArray(scores, SCORE_BUFFER, lastIndex+1, index);
+ fillArray(scores, SCORE_BUFFER, scoreIndex+1, index);
}
else {
- fillArray(scores, SCORE_NO_MATCH, lastIndex+1, index);
+ fillArray(scores, SCORE_NO_MATCH, scoreIndex+1, index);
}
-
scores[index] = SCORE_MATCH;
- lastIndex = index;
- }
- var trailingScore = started ? SCORE_TRAILING_BUT_STARTED : SCORE_TRAILING;
- fillArray(scores, trailingScore, lastIndex+1);
- return scores;
+ // consume matched string and continue search
+ searchIndex = index;
+ this._scoreAll(string, search, abbrev, searchIndex, abbrIndex, scores, allScores);
+ }
}
};
@@ -76,13 +111,11 @@ var LiquidMetal = function() {
function isNewWord(string, index) {
var c = string.charAt(index-1);
- return (c == " " || c == "\t");
+ return (WORD_SEPARATORS.indexOf(c) != -1);
}
function fillArray(array, value, from, to) {
- from = Math.max(from || 0, 0);
- to = Math.min(to || array.length, array.length);
for (var i = from; i < to; i++) { array[i] = value; }
return array;
}
-}();
+})();

0 comments on commit ba7240a

Please sign in to comment.