UNPKG

motion

Version:

motion - moving development forward

129 lines (107 loc) 5.05 kB
###! * string_score.js: Quicksilver-like string scoring algorithm. * * Copyright (C) 2009-2011 Joshaven Potter <yourtech@gmail.com> * Copyright (C) 2010-2011 Yesudeep Mangalapilly <yesudeep@gmail.com> * MIT license: http://www.opensource.org/licenses/mit-license.php ### # Special thanks to Lachie Cox and Quicksilver for inspiration. # # Compilation notes: # # 1. Compile with the `-b -c` flags to the coffee-script compiler # `String.prototype.score` # ------------------------ String::score = (abbreviation) -> # **Size optimization notes**: # Declaring `string` before checking for an exact match # does not affect the speed and reduces size because `this` # occurs only once in the code as a result. string = this # Perfect match if the string equals the abbreviation. return 1.0 if string == abbreviation # Initializing variables. string_length = string.length total_character_score = 0 # Awarded only if the string and the abbreviation have a common prefix. should_award_common_prefix_bonus = 0 #no #### Sum character scores # Add up scores for each character in the abbreviation. for c, i in abbreviation # Find the index of current character (case-insensitive) in remaining part of string. index_c_lowercase = string.indexOf c.toLowerCase() index_c_uppercase = string.indexOf c.toUpperCase() min_index = Math.min index_c_lowercase, index_c_uppercase index_in_string = if min_index > -1 then min_index else Math.max index_c_lowercase, index_c_uppercase #### Identical strings # Bail out if current character is not found (case-insensitive) in remaining part of string. # # **Possible size optimization**: # Replace `index_in_string == -1` with `index_in_string < 0` # which has fewer characters and should have identical performance. return 0 if index_in_string == -1 # Set base score for current character. character_score = 0.1 #### Case-match bonus # If the current abbreviation character has the same case # as that of the character in the string, we add a bonus. # # **Optimization notes**: # `charAt` was replaced with an index lookup here because # the latter results in smaller and faster code without # breaking any tests. if string[index_in_string] == c character_score += 0.1 #### Consecutive character match and common prefix bonuses # Increase the score when each consecutive character of # the abbreviation matches the first character of the # remaining string. # # **Size optimization disabled (truthiness shortened)**: # It produces smaller code but is slower. # # if !index_in_string if index_in_string == 0 character_score += 0.8 # String and abbreviation have common prefix, so award bonus. # # **Size optimization disabled (truthiness shortened)**: # It produces smaller code but is slower. # # if !i if i == 0 should_award_common_prefix_bonus = 1 #yes #### Acronym bonus # Typing the first character of an acronym is as # though you preceded it with two perfect character # matches. # # **Size optimization disabled**: # `string.charAt(index)` wasn't replaced with `string[index]` # in this case even though the latter results in smaller # code (when minified) because the former is faster, and # the gain out of replacing it is negligible. if string.charAt(index_in_string - 1) == ' ' character_score += 0.8 # * Math.min(index_in_string, 5) # Cap bonus at 0.4 * 5 # Left trim the matched part of the string # (forces sequential matching). string = string.substring(index_in_string + 1, string_length) # Add to total character score. total_character_score += character_score # **Feature disabled**: # Uncomment the following to weigh smaller words higher. # # return total_character_score / string_length abbreviation_length = abbreviation.length abbreviation_score = total_character_score / abbreviation_length #### Reduce penalty for longer strings # **Optimization notes (code inlined)**: # # percentage_of_matched_string = abbreviation_length / string_length # word_score = abbreviation_score * percentage_of_matched_string # final_score = (word_score + abbreviation_score) / 2 final_score = ((abbreviation_score * (abbreviation_length / string_length)) + abbreviation_score) / 2 #### Award common prefix bonus if should_award_common_prefix_bonus and (final_score + 0.1 < 1) final_score += 0.1 return final_score