Skip to content

Instantly share code, notes, and snippets.

@mislav
Created January 20, 2015 01:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mislav/ea363384fd14a36b5960 to your computer and use it in GitHub Desktop.
Save mislav/ea363384fd14a36b5960 to your computer and use it in GitHub Desktop.
Fuzzy scoring algorithm adopted from Selecta as used on GitHub.com
# Get the shortest match (least distance between start and end index) for all
# the query characters in the given text.
#
# Returns an array in format [firstIndex, matchLength, [matchIndexes]]
shortestMatch = (text, queryChars) ->
starts = allIndexesOf(text, queryChars[0])
return if starts.length is 0
return [starts[0], 1, []] if queryChars.length is 1
match = null
for start in starts when indexes = indexesOfChars(text, queryChars, start + 1)
length = indexes[indexes.length - 1] - start
match = [start, length, indexes] if !match or length < match[1]
return match
# Find all indexes of character inside a string.
allIndexesOf = (string, char) ->
index = 0
index++ while (index = string.indexOf(char, index)) > -1
# Find all indexes of characters of query string in order.
indexesOfChars = (string, chars, index) ->
indexes = []
for i in [1...chars.length]
index = string.indexOf(chars[i], index)
return if index is -1
indexes.push index++
indexes
fixedMaxScore = -> 2.0
# Initializes the scorer object by preparing the query.
#
# Returns an object with the `score` method that takes text to be scored
# against the query.
fuzzyScorer = (query) ->
if query
queryChars = query.toLowerCase().split("")
score = (text) ->
return 0.0 unless text
match = shortestMatch(text, queryChars)
return 0.0 unless match
# Penalize matches that are more spread apart
value = query.length / match[1]
# Penalize matches further from the beginning of string
value = value / (match[0]/2 + 1)
else
score = fixedMaxScore
return {score}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment