FORKED FROM / BASED ON fuzzysearch
by Nicolas Bevacqua
Tiny, fast, and dependency-less fuzzy search + highlighting in JavaScript
Fuzzy searching allows for flexibly matching a string with partial input, useful for filtering data very quickly based on lightweight user input.
Head here for a simple working demo.
npm install --save fuzzyhighlight
or
yarn add fuzzyhighlight
You may import fuzzyhighlight
as a whole, or its methods separately.
import * as fuzzyhighlight from 'fuzzyhighlight'
import {
fuzzyHighlight,
fuzzySearch,
highlight,
isFuzzyMatch
} from 'fuzzyhighlight'
interface Index {
start: number,
end: number
}
interface Result {
isMatch: boolean,
indexes: Index[],
score: number
}
interface Options {
caseSensitive?: boolean,
tag?: string
}
isFuzzyMatch(needle: string, haystack: string|object, options?: Options) : boolean
Returns true
if needle
matches haystack
using a fuzzy-search algorithm. The method will return true
only if each character in the needle
can be found in the haystack
and occurs after the preceding matches.
If the provided haystack
is an object instead of a string, the method will return true
if any of the object's values fuzzy-matches the needle
.
Note that this program doesn't implement levenshtein distance, but rather a simplified version where there's no approximation.
Fuzzy-search is case insentitive by default, you can make it otherwise by providing options
with { caseSensitive: true }
.
isFuzzyMatch('twl', 'cartwheel') // true
isFuzzyMatch('art', 'cartwheel') // true
isFuzzyMatch('CaRt', 'cartwheel') // true
isFuzzyMatch('cw', 'cartwheel') // true
isFuzzyMatch('eE', 'cartwheel') // true
isFuzzyMatch('eeel', 'cartwheel') // false
isFuzzyMatch('dog', 'cartwheel') // false
isFuzzyMatch('CaRt', 'cartwheel', { caseSensitive: true }) // false
isFuzzyMatch('eE', 'cartwheel', { caseSensitive: true }) // false
isFuzzyMatch('car', { foo: 'cartwheel', bar: 'bar' }) // true
isFuzzyMatch('cwhl', { foo: 'foo', bar: 'cartwheel' }) // true
isFuzzyMatch('cWheEl', { foo: 'cartwheel', bar: 'cartwheel' }) // true
isFuzzyMatch('car', {}) // false
isFuzzyMatch('car', { foo: 'foo', bar: 'bar' }) // false
isFuzzyMatch('CarT', { foo: 'foo', bar: 'cartwheel' }, { caseSensitive: true }) // true
fuzzyHighlight(needle: string, haystack: string, options?: Options) : string
Returns haystack
string with needle
's matching characters wrapped in a <strong>
tag by default.
Fuzzy-search is case insentitive by default, you can make it otherwise by providing options
with { caseSensitive: true }
.
You can specify the tag
you want to wrap the needle
's matching characters with; otherwise, <strong>
is used by default. Mind that it doesn't have to be a valid HTML tag.
fuzzyHighlight('car', 'cartwheel') // <strong>car</strong>twheel
fuzzyHighlight('twl', 'cartwheel') // car<strong>tw</strong>hee<strong>l</strong>
fuzzyHighlight('CaRe', 'cartwheel') // <strong>car</strong>wh<strong>e</strong>el
fuzzyHighlight('CaRe', 'cartwheel', { caseSensitive: true }) // cartwheel
fuzzyHighlight('cw', 'cartwheel', { tag: 'em' }) // <em>c</em>art<em>w</em>heel
fuzzyHighlight('ee', 'cartwheel', { tag: 'i' }) // cartwh<i>ee</i>l
fuzzyHighlight('wheel', 'cartwheel', { tag: 'foo' }) // cartwh<foo>ee</foo>l
fuzzySearch(needle: string, haystack: string, options?: Options) : Result
Returns an object of type Result
, where isMatch
is true
if needle
matches haystack
using a fuzzy-search algorithm.
In turn, indexes
contains an array of type Index
, which represents the start
and end
indexes of the needle
's characters matched in the haystack
. The purpose of this array is mostly to be used by the highlight
method.
Finally score
is the length of the longest slice of consecutively matching characters of needle
inside haystack
(i.e. the maximum difference between its index pairs). The score is useful when matching a list of entries against the same needle
-which is most probably everyone's use case-, because you can use it to sort the positive matches from best to worst score.
NOTE: The working demo implements this sorting behavior if you want to try it out.
Fuzzy-search is case insentitive by default, you can make it otherwise by providing options
with { caseSensitive: true }
.
fuzzySearch('twl', 'cartwheel')
// {
// isMatch: true,
// indexes: [{ start: 3, end: 5}, { start: 8, end: 9 }],
// score: 2
// }
fuzzySearch('art', 'cartwheel')
// {
// isMatch: true,
// indexes: [{ start: 1, end: 4}],
// score: 3
// }
fuzzySearch('cw', 'cartwheel')
// {
// isMatch: true,
// indexes: [{ start: 0, end: 1}, { start: 4, end: 5 }]
// score: 1
// }
fuzzySearch('ee', 'cartwheel')
// {
// isMatch: true,
// indexes: [{ start: 6, end: 8}]
// score: 2
// }
fuzzySearch('eeel', 'cartwheel')
// {
// isMatch: false,
// indexes: []
// score: 0
// }
fuzzySearch('CaRt', 'cartwheel', { caseSensitive: true })
// {
// isMatch: false,
// indexes: []
// score: 0
// }
fuzzySearch('dog', 'cartwheel')
// {
// isMatch: false,
// indexes: [],
// score: 0
// }
highlight(label: string, indexes: Index[], tag: string = 'strong')
Returns label
with its characters in-between indexes
wrapped in the given tag
. If tag
is not specified, <strong>
is used by default.
The indexes
parameter should be of type Index[]
.
highlight('cartwheel', [{ start: 0, end: 3 }]) // <strong>car</strong>twheel
highlight('cartwheel', [{ start: 1, end: 4}]) // car<strong>tw</strong>hee<strong>l</strong>
highlight('cartwheel', [{ start: 0, end: 1}, { start: 4, end: 5 }], 'b') // <b>c</b>art<b>w</b>heel
highlight('cartwheel', [{ start: 6, end: 8}], 'i') // cartwh<i>ee</i>l
The current implementation uses the algorithm suggested by Mr. Aleph, a crazy russian compiler engineer working at V8.
MIT