1 | // MODIFIED BY NS/CJ - Don't extend the prototype of String
|
2 | // MODIFIED BY CJ - Remove start_of_string_bonus
|
3 |
|
4 | /*!
|
5 | * string_score.js: String Scoring Algorithm 0.1.10
|
6 | *
|
7 | * http://joshaven.com/string_score
|
8 | * https://github.com/joshaven/string_score
|
9 | *
|
10 | * Copyright (C) 2009-2011 Joshaven Potter <yourtech@gmail.com>
|
11 | * Special thanks to all of the contributors listed here https://github.com/joshaven/string_score
|
12 | * MIT license: http://www.opensource.org/licenses/mit-license.php
|
13 | *
|
14 | * Date: Tue Mar 1 2011
|
15 | */
|
16 |
|
17 | /**
|
18 | * Scores a string against another string.
|
19 | * 'Hello World'.score('he'); //=> 0.5931818181818181
|
20 | * 'Hello World'.score('Hello'); //=> 0.7318181818181818
|
21 | */
|
22 | module.exports = function(string, abbreviation) {
|
23 | // If the string is equal to the abbreviation, perfect match.
|
24 | if (string == abbreviation) {return 1;}
|
25 |
|
26 | var total_character_score = 0,
|
27 | abbreviation_length = abbreviation.length,
|
28 | string_length = string.length,
|
29 | start_of_string_bonus,
|
30 | abbreviation_score,
|
31 | final_score;
|
32 |
|
33 | // Walk through abbreviation and add up scores.
|
34 | for (var i = 0,
|
35 | character_score/* = 0*/,
|
36 | index_in_string/* = 0*/,
|
37 | c/* = ''*/,
|
38 | index_c_lowercase/* = 0*/,
|
39 | index_c_uppercase/* = 0*/,
|
40 | min_index/* = 0*/;
|
41 | i < abbreviation_length;
|
42 | ++i) {
|
43 |
|
44 | // Find the first case-insensitive match of a character.
|
45 | c = abbreviation.charAt(i);
|
46 |
|
47 | index_c_lowercase = string.indexOf(c.toLowerCase());
|
48 | index_c_uppercase = string.indexOf(c.toUpperCase());
|
49 | min_index = Math.min(index_c_lowercase, index_c_uppercase);
|
50 | index_in_string = (min_index > -1) ? min_index : Math.max(index_c_lowercase, index_c_uppercase);
|
51 |
|
52 | if (index_in_string === -1) {
|
53 | return 0;
|
54 | } else {
|
55 | character_score = 0.1;
|
56 | }
|
57 |
|
58 | // Set base score for matching 'c'.
|
59 |
|
60 | // Same case bonus.
|
61 | if (string[index_in_string] === c) {
|
62 | character_score += 0.1;
|
63 | }
|
64 |
|
65 | // Consecutive letter & start-of-string Bonus
|
66 | if (index_in_string === 0) {
|
67 | // Increase the score when matching first character of the remainder of the string
|
68 | character_score += 0.6;
|
69 | if (i === 0) {
|
70 | // If match is the first character of the string
|
71 | // & the first character of abbreviation, add a
|
72 | // start-of-string match bonus.
|
73 | // start_of_string_bonus = 1 //true;
|
74 | }
|
75 | }
|
76 | else {
|
77 | // Acronym Bonus
|
78 | // Weighing Logic: Typing the first character of an acronym is as if you
|
79 | // preceded it with two perfect character matches.
|
80 | if (string.charAt(index_in_string - 1) === ' ') {
|
81 | character_score += 0.8; // * Math.min(index_in_string, 5); // Cap bonus at 0.4 * 5
|
82 | }
|
83 | }
|
84 |
|
85 | // Left trim the already matched part of the string
|
86 | // (forces sequential matching).
|
87 | string = string.substring(index_in_string + 1, string_length);
|
88 |
|
89 | total_character_score += character_score;
|
90 | } // end of for loop
|
91 |
|
92 | // Uncomment to weigh smaller words higher.
|
93 | // return total_character_score / string_length;
|
94 |
|
95 | abbreviation_score = total_character_score / abbreviation_length;
|
96 | //percentage_of_matched_string = abbreviation_length / string_length;
|
97 | //word_score = abbreviation_score * percentage_of_matched_string;
|
98 |
|
99 | // Reduce penalty for longer strings.
|
100 | //final_score = (word_score + abbreviation_score) / 2;
|
101 | final_score = ((abbreviation_score * (abbreviation_length / string_length)) + abbreviation_score) / 2;
|
102 |
|
103 | if (start_of_string_bonus && (final_score + 0.15 < 1)) {
|
104 | final_score += 0.15;
|
105 | }
|
106 |
|
107 | return final_score;
|
108 | };
|