@@ -165,27 +165,30 @@ function uFuzzy(opts) {
165
165
_intraTrn = 0 ,
166
166
_intraDel = 0 ;
167
167
168
- let plen = p . length ;
169
-
170
- // prevent junk matches by requiring stricter rules for short terms
171
- if ( plen <= 4 ) {
172
- if ( plen >= 3 ) {
173
- // one swap in non-first char when 3-4 chars
174
- _intraTrn = Math . min ( intraTrn , 1 ) ;
175
-
176
- // or one insertion when 4 chars
177
- if ( plen == 4 )
178
- _intraIns = Math . min ( intraIns , 1 ) ;
168
+ // only-digits strings should match exactly, else special rules for short strings
169
+ if ( / [ ^ \d ] / . test ( p ) ) {
170
+ let plen = p . length ;
171
+
172
+ // prevent junk matches by requiring stricter rules for short terms
173
+ if ( plen <= 4 ) {
174
+ if ( plen >= 3 ) {
175
+ // one swap in non-first char when 3-4 chars
176
+ _intraTrn = Math . min ( intraTrn , 1 ) ;
177
+
178
+ // or one insertion when 4 chars
179
+ if ( plen == 4 )
180
+ _intraIns = Math . min ( intraIns , 1 ) ;
181
+ }
182
+ // else exact match when 1-2 chars
183
+ }
184
+ // use supplied opts
185
+ else {
186
+ _intraSlice = intraSlice ;
187
+ _intraIns = intraIns ,
188
+ _intraSub = intraSub ,
189
+ _intraTrn = intraTrn ,
190
+ _intraDel = intraDel ;
179
191
}
180
- // else exact match when 1-2 chars
181
- }
182
- // use supplied opts
183
- else {
184
- _intraSlice = intraSlice ;
185
- _intraIns = intraIns ,
186
- _intraSub = intraSub ,
187
- _intraTrn = intraTrn ,
188
- _intraDel = intraDel ;
189
192
}
190
193
191
194
return {
@@ -223,6 +226,8 @@ function uFuzzy(opts) {
223
226
return needle . split ( interSplit ) . filter ( t => t != '' ) . map ( v => v === EXACT_HERE ? exacts [ j ++ ] : v ) ;
224
227
} ;
225
228
229
+ const NUM_OR_ALPHA_RE = / [ ^ \d ] + | \d + / g;
230
+
226
231
const prepQuery = ( needle , capt = 0 , interOR = false ) => {
227
232
// split on punct, whitespace, num-alpha, and upper-lower boundaries
228
233
let parts = split ( needle ) ;
@@ -243,64 +248,72 @@ function uFuzzy(opts) {
243
248
// allows single mutations within each term
244
249
if ( intraMode == 1 ) {
245
250
reTpl = parts . map ( ( p , pi ) => {
246
- let {
247
- intraSlice,
248
- intraIns,
249
- intraSub,
250
- intraTrn,
251
- intraDel,
252
- } = intraRules ( p ) ;
253
-
254
- if ( intraIns + intraSub + intraTrn + intraDel == 0 )
255
- return p + contrs [ pi ] ;
256
-
257
251
if ( p [ 0 ] === '"' )
258
252
return escapeRegExp ( p . slice ( 1 , - 1 ) ) ;
259
253
260
- let [ lftIdx , rgtIdx ] = intraSlice ;
261
- let lftChar = p . slice ( 0 , lftIdx ) ; // prefix
262
- let rgtChar = p . slice ( rgtIdx ) ; // suffix
254
+ let reTpl = '' ;
263
255
264
- let chars = p . slice ( lftIdx , rgtIdx ) ;
256
+ // split into numeric and alpha parts, so numbers are only matched as following punct or alpha boundaries, without swaps or insertions
257
+ for ( let m of p . matchAll ( NUM_OR_ALPHA_RE ) ) {
258
+ let p = m [ 0 ] ;
265
259
266
- // neg lookahead to prefer matching 'Test' instead of 'tTest' in ManifestTest or fittest
267
- // but skip when search term contains leading repetition (aardvark, aaa)
268
- if ( intraIns == 1 && lftChar . length == 1 && lftChar != chars [ 0 ] )
269
- lftChar += '(?!' + lftChar + ')' ;
260
+ let {
261
+ intraSlice,
262
+ intraIns,
263
+ intraSub,
264
+ intraTrn,
265
+ intraDel,
266
+ } = intraRules ( p ) ;
270
267
271
- let numChars = chars . length ;
268
+ if ( intraIns + intraSub + intraTrn + intraDel == 0 )
269
+ reTpl += p + contrs [ pi ] ;
270
+ else {
271
+ let [ lftIdx , rgtIdx ] = intraSlice ;
272
+ let lftChar = p . slice ( 0 , lftIdx ) ; // prefix
273
+ let rgtChar = p . slice ( rgtIdx ) ; // suffix
272
274
273
- let variants = [ p ] ;
275
+ let chars = p . slice ( lftIdx , rgtIdx ) ;
274
276
275
- // variants with single char substitutions
276
- if ( intraSub ) {
277
- for ( let i = 0 ; i < numChars ; i ++ )
278
- variants . push ( lftChar + chars . slice ( 0 , i ) + intraChars + chars . slice ( i + 1 ) + rgtChar ) ;
279
- }
277
+ // neg lookahead to prefer matching 'Test' instead of 'tTest' in ManifestTest or fittest
278
+ // but skip when search term contains leading repetition (aardvark, aaa)
279
+ if ( intraIns == 1 && lftChar . length == 1 && lftChar != chars [ 0 ] )
280
+ lftChar += '(?!' + lftChar + ')' ;
280
281
281
- // variants with single transpositions
282
- if ( intraTrn ) {
283
- for ( let i = 0 ; i < numChars - 1 ; i ++ ) {
284
- if ( chars [ i ] != chars [ i + 1 ] )
285
- variants . push ( lftChar + chars . slice ( 0 , i ) + chars [ i + 1 ] + chars [ i ] + chars . slice ( i + 2 ) + rgtChar ) ;
286
- }
287
- }
282
+ let numChars = chars . length ;
288
283
289
- // variants with single char omissions
290
- if ( intraDel ) {
291
- for ( let i = 0 ; i < numChars ; i ++ )
292
- variants . push ( lftChar + chars . slice ( 0 , i + 1 ) + '?' + chars . slice ( i + 1 ) + rgtChar ) ;
293
- }
284
+ let variants = [ p ] ;
294
285
295
- // variants with single char insertions
296
- if ( intraIns ) {
297
- let intraInsTpl = lazyRepeat ( intraChars , 1 ) ;
286
+ // variants with single char substitutions
287
+ if ( intraSub ) {
288
+ for ( let i = 0 ; i < numChars ; i ++ )
289
+ variants . push ( lftChar + chars . slice ( 0 , i ) + intraChars + chars . slice ( i + 1 ) + rgtChar ) ;
290
+ }
298
291
299
- for ( let i = 0 ; i < numChars ; i ++ )
300
- variants . push ( lftChar + chars . slice ( 0 , i ) + intraInsTpl + chars . slice ( i ) + rgtChar ) ;
301
- }
292
+ // variants with single transpositions
293
+ if ( intraTrn ) {
294
+ for ( let i = 0 ; i < numChars - 1 ; i ++ ) {
295
+ if ( chars [ i ] != chars [ i + 1 ] )
296
+ variants . push ( lftChar + chars . slice ( 0 , i ) + chars [ i + 1 ] + chars [ i ] + chars . slice ( i + 2 ) + rgtChar ) ;
297
+ }
298
+ }
302
299
303
- let reTpl = '(?:' + variants . join ( '|' ) + ')' + contrs [ pi ] ;
300
+ // variants with single char omissions
301
+ if ( intraDel ) {
302
+ for ( let i = 0 ; i < numChars ; i ++ )
303
+ variants . push ( lftChar + chars . slice ( 0 , i + 1 ) + '?' + chars . slice ( i + 1 ) + rgtChar ) ;
304
+ }
305
+
306
+ // variants with single char insertions
307
+ if ( intraIns ) {
308
+ let intraInsTpl = lazyRepeat ( intraChars , 1 ) ;
309
+
310
+ for ( let i = 0 ; i < numChars ; i ++ )
311
+ variants . push ( lftChar + chars . slice ( 0 , i ) + intraInsTpl + chars . slice ( i ) + rgtChar ) ;
312
+ }
313
+
314
+ reTpl += '(?:' + variants . join ( '|' ) + ')' + contrs [ pi ] ;
315
+ }
316
+ }
304
317
305
318
// console.log(reTpl);
306
319
0 commit comments