1 /**
  2  * Copyright (c) 2012.
  3  * Licensed under the MIT License.
  4  * See LICENSE for detailed information.
  5  *
  6  * JavaScript
  7  *
  8  * @fileoverview        Methods to compute string metrics.
  9  * @version             0.3.0
 10  * @author              Jonathan Ruttan <jonruttan@iwastenotsystems.com>
 11  * @license             http://www.opensource.org/licenses/mit-license.php The MIT License.
 12  * @package             String.metrics
 13  *
 14  */
 15 // TODO: Finalize Node namespace settings
 16 // +[Fix String.metrics namespace hack]--JR
 17 (function(exports) {
 18     'use strict';
 19 
 20     /**
 21      * @namespace Contains methods to compute string metrics.
 22      * @name String.metrics
 23      */
 24     var fns = exports.metrics = {
 25         /**
 26          * Compute the distance between two strings as a fraction of the length
 27          * of the longer of the two strings.
 28          *
 29          * @public
 30          * @memberOf                  String.metrics
 31          * @param   {String} str1     One of the strings to score against.
 32          * @param   {String} str2     One of the strings to score against.
 33          * @param   {Number|Function} distance
 34          *                            An integer distance between strings,
 35          *                            or a function to compute the distance.
 36          * @return  {Number}          Returns the computed distance between the
 37          *                            two argument strings as a fraction.
 38          */
 39         fraction: function( str1, str2, distance ) {
 40             var length = Math.max(str1.length, str2.length);
 41             return length ? 1 - (typeof distance === 'function' ?
 42                         distance( str1, str2 ) : distance) / length : 1;
 43         },
 44 
 45         /**
 46          * Compute the Levenshtein distance between two strings.
 47          *
 48          * @public
 49          * @memberOf              String.metrics
 50          * @see Source: <a href="http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript">Wikibooks:Algorithm Implementation/Strings/Levenshtein distance</a>
 51          * @see Wikipedia: <a href="http://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance</a>
 52          * @param   {String} str1 One of the strings to score against.
 53          * @param   {String} str2 One of the strings to score against.
 54          * @return  {Number}      Returns the computed Levenshtein distance
 55          *                        between the two argument strings.
 56          */
 57         levenshteinDistance: function(str1, str2) {
 58             if (str1.length === 0) return str2.length;
 59             if (str2.length === 0) return str1.length;
 60 
 61             var matrix = [];
 62 
 63             // increment along the first column of each row
 64             var i;
 65             for (i = 0; i <= str2.length; i++) {
 66                 matrix[i] = [i];
 67             }
 68 
 69             // increment each column in the first row
 70             var j;
 71             for (j = 0; j <= str1.length; j++) {
 72                 matrix[0][j] = j;
 73             }
 74 
 75             // Fill in the rest of the matrix
 76             for (i = 1; i <= str2.length; i++) {
 77                 for (j = 1; j <= str1.length; j++) {
 78                     if (str2.charAt(i - 1) == str1.charAt(j - 1)) {
 79                         matrix[i][j] = matrix[i - 1][j - 1];
 80                     } else {
 81                         matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
 82                                 Math.min(matrix[i][j - 1] + 1, // insertion
 83                                     matrix[i - 1][j] + 1)); // deletion
 84                     }
 85                 }
 86             }
 87 
 88             return matrix[str2.length][str1.length];
 89         },
 90 
 91         /**
 92          * Compute the Levenshtein distance between two strings as a fraction
 93          * of the length of the longer of the two strings.
 94          * .
 95          *
 96          * @public
 97          * @memberOf              String.metrics
 98          * @param   {String} str1 One of the strings to score against.
 99          * @param   {String} str2 One of the strings to score against.
100          * @return  {Number}      Returns the computed distance between the two
101          *                        argument strings as a fraction.
102          */
103         levenshteinFraction: function( str1, str2 ) {
104             return exports.metrics.fraction(str1, str2,
105                     exports.metrics.levenshteinDistance);
106         }
107     };
108 })(typeof exports === 'undefined' ? String : exports);
109