source: frontend/node_modules/didyoumean/didYouMean-1.2.1.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 9.3 KB
Line 
1/*
2
3didYouMean.js - A simple JavaScript matching engine
4===================================================
5
6[Available on GitHub](https://github.com/dcporter/didyoumean.js).
7
8A super-simple, highly optimized JS library for matching human-quality input to a list of potential
9matches. You can use it to suggest a misspelled command-line utility option to a user, or to offer
10links to nearby valid URLs on your 404 page. (The examples below are taken from a personal project,
11my [HTML5 business card](http://dcporter.aws.af.cm/me), which uses didYouMean.js to suggest correct
12URLs from misspelled ones, such as [dcporter.aws.af.cm/me/instagarm](http://dcporter.aws.af.cm/me/instagarm).)
13Uses the [Levenshtein distance algorithm](https://en.wikipedia.org/wiki/Levenshtein_distance).
14
15didYouMean.js works in the browser as well as in node.js. To install it for use in node:
16
17```
18npm install didyoumean
19```
20
21
22Examples
23--------
24
25Matching against a list of strings:
26```
27var input = 'insargrm'
28var list = ['facebook', 'twitter', 'instagram', 'linkedin'];
29console.log(didYouMean(input, list));
30> 'instagram'
31// The method matches 'insargrm' to 'instagram'.
32
33input = 'google plus';
34console.log(didYouMean(input, list));
35> null
36// The method was unable to find 'google plus' in the list of options.
37```
38
39Matching against a list of objects:
40```
41var input = 'insargrm';
42var list = [ { id: 'facebook' }, { id: 'twitter' }, { id: 'instagram' }, { id: 'linkedin' } ];
43var key = 'id';
44console.log(didYouMean(input, list, key));
45> 'instagram'
46// The method returns the matching value.
47
48didYouMean.returnWinningObject = true;
49console.log(didYouMean(input, list, key));
50> { id: 'instagram' }
51// The method returns the matching object.
52```
53
54
55didYouMean(str, list, [key])
56----------------------------
57
58- str: The string input to match.
59- list: An array of strings or objects to match against.
60- key (OPTIONAL): If your list array contains objects, you must specify the key which contains the string
61 to match against.
62
63Returns: the closest matching string, or null if no strings exceed the threshold.
64
65
66Options
67-------
68
69Options are set on the didYouMean function object. You may change them at any time.
70
71### threshold
72
73 By default, the method will only return strings whose edit distance is less than 40% (0.4x) of their length.
74 For example, if a ten-letter string is five edits away from its nearest match, the method will return null.
75
76 You can control this by setting the "threshold" value on the didYouMean function. For example, to set the
77 edit distance threshold to 50% of the input string's length:
78
79 ```
80 didYouMean.threshold = 0.5;
81 ```
82
83 To return the nearest match no matter the threshold, set this value to null.
84
85### thresholdAbsolute
86
87 This option behaves the same as threshold, but instead takes an integer number of edit steps. For example,
88 if thresholdAbsolute is set to 20 (the default), then the method will only return strings whose edit distance
89 is less than 20. Both options apply.
90
91### caseSensitive
92
93 By default, the method will perform case-insensitive comparisons. If you wish to force case sensitivity, set
94 the "caseSensitive" value to true:
95
96 ```
97 didYouMean.caseSensitive = true;
98 ```
99
100### nullResultValue
101
102 By default, the method will return null if there is no sufficiently close match. You can change this value here.
103
104### returnWinningObject
105
106 By default, the method will return the winning string value (if any). If your list contains objects rather
107 than strings, you may set returnWinningObject to true.
108
109 ```
110 didYouMean.returnWinningObject = true;
111 ```
112
113 This option has no effect on lists of strings.
114
115### returnFirstMatch
116
117 By default, the method will search all values and return the closest match. If you're simply looking for a "good-
118 enough" match, you can set your thresholds appropriately and set returnFirstMatch to true to substantially speed
119 things up.
120
121
122License
123-------
124
125didYouMean copyright (c) 2013-2014 Dave Porter.
126
127Licensed under the Apache License, Version 2.0 (the "License");
128you may not use this file except in compliance with the License.
129You may obtain a copy of the License
130[here](http://www.apache.org/licenses/LICENSE-2.0).
131
132Unless required by applicable law or agreed to in writing, software
133distributed under the License is distributed on an "AS IS" BASIS,
134WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135See the License for the specific language governing permissions and
136limitations under the License.
137
138*/
139(function() {
140 "use strict";
141
142 // The didYouMean method.
143 function didYouMean(str, list, key) {
144 if (!str) return null;
145
146 // If we're running a case-insensitive search, smallify str.
147 if (!didYouMean.caseSensitive) { str = str.toLowerCase(); }
148
149 // Calculate the initial value (the threshold) if present.
150 var thresholdRelative = didYouMean.threshold === null ? null : didYouMean.threshold * str.length,
151 thresholdAbsolute = didYouMean.thresholdAbsolute,
152 winningVal;
153 if (thresholdRelative !== null && thresholdAbsolute !== null) winningVal = Math.min(thresholdRelative, thresholdAbsolute);
154 else if (thresholdRelative !== null) winningVal = thresholdRelative;
155 else if (thresholdAbsolute !== null) winningVal = thresholdAbsolute;
156 else winningVal = null;
157
158 // Get the edit distance to each option. If the closest one is less than 40% (by default) of str's length,
159 // then return it.
160 var winner, candidate, testCandidate, val,
161 i, len = list.length;
162 for (i = 0; i < len; i++) {
163 // Get item.
164 candidate = list[i];
165 // If there's a key, get the candidate value out of the object.
166 if (key) { candidate = candidate[key]; }
167 // Gatekeep.
168 if (!candidate) { continue; }
169 // If we're running a case-insensitive search, smallify the candidate.
170 if (!didYouMean.caseSensitive) { testCandidate = candidate.toLowerCase(); }
171 else { testCandidate = candidate; }
172 // Get and compare edit distance.
173 val = getEditDistance(str, testCandidate, winningVal);
174 // If this value is smaller than our current winning value, OR if we have no winning val yet (i.e. the
175 // threshold option is set to null, meaning the caller wants a match back no matter how bad it is), then
176 // this is our new winner.
177 if (winningVal === null || val < winningVal) {
178 winningVal = val;
179 // Set the winner to either the value or its object, depending on the returnWinningObject option.
180 if (key && didYouMean.returnWinningObject) winner = list[i];
181 else winner = candidate;
182 // If we're returning the first match, return it now.
183 if (didYouMean.returnFirstMatch) return winner;
184 }
185 }
186
187 // If we have a winner, return it.
188 return winner || didYouMean.nullResultValue;
189 }
190
191 // Set default options.
192 didYouMean.threshold = 0.4;
193 didYouMean.thresholdAbsolute = 20;
194 didYouMean.caseSensitive = false;
195 didYouMean.nullResultValue = null;
196 didYouMean.returnWinningObject = null;
197 didYouMean.returnFirstMatch = false;
198
199 // Expose.
200 // In node...
201 if (typeof module !== 'undefined' && module.exports) {
202 module.exports = didYouMean;
203 }
204 // Otherwise...
205 else {
206 window.didYouMean = didYouMean;
207 }
208
209 var MAX_INT = Math.pow(2,32) - 1; // We could probably go higher than this, but for practical reasons let's not.
210 function getEditDistance(a, b, max) {
211 // Handle null or undefined max.
212 max = max || max === 0 ? max : MAX_INT;
213
214 var lena = a.length;
215 var lenb = b.length;
216
217 // Fast path - no A or B.
218 if (lena === 0) return Math.min(max + 1, lenb);
219 if (lenb === 0) return Math.min(max + 1, lena);
220
221 // Fast path - length diff larger than max.
222 if (Math.abs(lena - lenb) > max) return max + 1;
223
224 // Slow path.
225 var matrix = [],
226 i, j, colMin, minJ, maxJ;
227
228 // Set up the first row ([0, 1, 2, 3, etc]).
229 for (i = 0; i <= lenb; i++) { matrix[i] = [i]; }
230
231 // Set up the first column (same).
232 for (j = 0; j <= lena; j++) { matrix[0][j] = j; }
233
234 // Loop over the rest of the columns.
235 for (i = 1; i <= lenb; i++) {
236 colMin = MAX_INT;
237 minJ = 1;
238 if (i > max) minJ = i - max;
239 maxJ = lenb + 1;
240 if (maxJ > max + i) maxJ = max + i;
241 // Loop over the rest of the rows.
242 for (j = 1; j <= lena; j++) {
243 // If j is out of bounds, just put a large value in the slot.
244 if (j < minJ || j > maxJ) {
245 matrix[i][j] = max + 1;
246 }
247
248 // Otherwise do the normal Levenshtein thing.
249 else {
250 // If the characters are the same, there's no change in edit distance.
251 if (b.charAt(i - 1) === a.charAt(j - 1)) {
252 matrix[i][j] = matrix[i - 1][j - 1];
253 }
254 // Otherwise, see if we're substituting, inserting or deleting.
255 else {
256 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // Substitute
257 Math.min(matrix[i][j - 1] + 1, // Insert
258 matrix[i - 1][j] + 1)); // Delete
259 }
260 }
261
262 // Either way, update colMin.
263 if (matrix[i][j] < colMin) colMin = matrix[i][j];
264 }
265
266 // If this column's minimum is greater than the allowed maximum, there's no point
267 // in going on with life.
268 if (colMin > max) return max + 1;
269 }
270 // If we made it this far without running into the max, then return the final matrix value.
271 return matrix[lenb][lena];
272 }
273
274})();
Note: See TracBrowser for help on using the repository browser.