@@ -112,3 +112,107 @@ $.extend( $.ui.autocomplete, {
112
112
} );
113
113
}
114
114
} );
115
+
116
+ /*
117
+ * Courtesy https://siderite.blogspot.com/2014/11/super-fast-and-accurate-string-distance.html
118
+ */
119
+
120
+ // Sift4 - common version
121
+ // online algorithm to compute the distance between two strings in O(n)
122
+ // maxOffset is the number of characters to search for matching letters
123
+ // maxDistance is the distance at which the algorithm should stop computing the value and just exit (the strings are too different anyway)
124
+ function sift4(s1, s2, maxOffset, maxDistance) {
125
+ if (!s1||!s1.length) {
126
+ if (!s2) {
127
+ return 0;
128
+ }
129
+ return s2.length;
130
+ }
131
+
132
+ if (!s2||!s2.length) {
133
+ return s1.length;
134
+ }
135
+
136
+ var l1=s1.length;
137
+ var l2=s2.length;
138
+
139
+ var c1 = 0; //cursor for string 1
140
+ var c2 = 0; //cursor for string 2
141
+ var lcss = 0; //largest common subsequence
142
+ var local_cs = 0; //local common substring
143
+ var trans = 0; //number of transpositions ('ab' vs 'ba')
144
+ var offset_arr=[]; //offset pair array, for computing the transpositions
145
+
146
+ while ((c1 < l1) && (c2 < l2)) {
147
+ if (s1.charAt(c1) == s2.charAt(c2)) {
148
+ local_cs++;
149
+ var isTrans=false;
150
+ //see if current match is a transposition
151
+ var i=0;
152
+ while (i<offset_arr.length) {
153
+ var ofs=offset_arr[i];
154
+ if (c1<=ofs.c1 || c2 <= ofs.c2) {
155
+ // when two matches cross, the one considered a transposition is the one with the largest difference in offsets
156
+ isTrans=Math.abs(c2-c1)>=Math.abs(ofs.c2-ofs.c1);
157
+ if (isTrans)
158
+ {
159
+ trans++;
160
+ } else
161
+ {
162
+ if (!ofs.trans) {
163
+ ofs.trans=true;
164
+ trans++;
165
+ }
166
+ }
167
+ break;
168
+ } else {
169
+ if (c1>ofs.c2 && c2>ofs.c1) {
170
+ offset_arr.splice(i,1);
171
+ } else {
172
+ i++;
173
+ }
174
+ }
175
+ }
176
+ offset_arr.push({
177
+ c1:c1,
178
+ c2:c2,
179
+ trans:isTrans
180
+ });
181
+ } else {
182
+ lcss+=local_cs;
183
+ local_cs=0;
184
+ if (c1!=c2) {
185
+ c1=c2=Math.min(c1,c2); //using min allows the computation of transpositions
186
+ }
187
+ //if matching characters are found, remove 1 from both cursors (they get incremented at the end of the loop)
188
+ //so that we can have only one code block handling matches
189
+ for (var i = 0; i < maxOffset && (c1+i<l1 || c2+i<l2); i++) {
190
+ if ((c1 + i < l1) && (s1.charAt(c1 + i) == s2.charAt(c2))) {
191
+ c1+= i-1;
192
+ c2--;
193
+ break;
194
+ }
195
+ if ((c2 + i < l2) && (s1.charAt(c1) == s2.charAt(c2 + i))) {
196
+ c1--;
197
+ c2+= i-1;
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ c1++;
203
+ c2++;
204
+ if (maxDistance)
205
+ {
206
+ var temporaryDistance=Math.max(c1,c2)-lcss+trans;
207
+ if (temporaryDistance>=maxDistance) return Math.round(temporaryDistance);
208
+ }
209
+ // this covers the case where the last match is on the last token in list, so that it can compute transpositions correctly
210
+ if ((c1 >= l1) || (c2 >= l2)) {
211
+ lcss+=local_cs;
212
+ local_cs=0;
213
+ c1=c2=Math.min(c1,c2);
214
+ }
215
+ }
216
+ lcss+=local_cs;
217
+ return Math.round(Math.max(l1,l2)- lcss +trans); //add the cost of transpositions to the final result
218
+ }
0 commit comments