Search

Bundled Algorithms

All eleven algorithms that ship with the package: their names, default thresholds, options and what each is for.

Every algorithm accepts { threshold, caseSensitive } from BaseAlgorithmOptions, on top of whatever it adds itself. threshold sets its default minimum confidence (overridable again at .register() time; see Thresholds and Confidence); caseSensitive is false by default.

FactoryNameDefault thresholdWhat it is for
NaiveSearch()naive0O(n) linear scan for an exact match.
NormalizedNaive()normalized-naive0Exact match after folding lookalike characters.
SubstringSearch()substring0Plain indexOf against every entry.
PrefixSearch()prefix0Type-ahead: entries that begin with the query.
KMP()kmp0Knuth–Morris–Pratt substring search, O(n + m) per entry.
BoyerMoore()boyer-moore0Boyer–Moore–Horspool: sublinear skipping on long entries.
Levenshtein()levenshtein0.7Edit distance: the one that catches typos.
JaroWinkler()jaro-winkler0.8Transpositions and shared prefixes, tuned for short strings.
NgramSearch()ngram0.4Trigram similarity; survives shuffled words.
SoundexSearch()soundex0Phonetic: entries that sound like the query.
FuzzySubsequence()fuzzy-subsequence0.2Command-palette style: "mbp" finds "MacBook Pro".

NaiveSearch

NaiveSearch(options?: BaseAlgorithmOptions): NaiveSearchAlgorithm;

O(n) linear scan: an exact match, case-folded like every other algorithm unless caseSensitive is set. Confidence is always 1; an entry either is the query or it isn’t. No options beyond the base threshold and caseSensitive.

NormalizedNaive

NormalizedNaive(options?: NormalizedNaiveOptions): NormalizedNaiveAlgorithm;

type NormalizedNaiveOptions = BaseAlgorithmOptions & {
	ambiguityGroups?: readonly string[];
	stripNonAlphanumeric?: boolean; // true by default
};

Exact match after folding characters that get mistaken for one another in serial numbers, model codes and OCR output: "MODEL-1O5B" matches "model 105 8". An entry that matches without folding scores 1; one that only matches after folding scores 0.9, so a true exact hit always outranks a normalized one. caseSensitive is accepted for consistency with the other algorithms, but has no effect: folding always lower-cases along the way.

Ambiguous character groups

The default groups, each folding to its first character in both cases:

["0O", "1lI|", "5S", "8B", "2Z", "6G"];

Replace them wholesale, and choose whether punctuation and whitespace survive the fold:

NormalizedNaive({
	ambiguityGroups: ["0OQ", "1lI|", "5S"],
	stripNonAlphanumeric: false, // true by default
});

ambiguityGroups replaces the defaults entirely rather than merging with them: pass every group you want, including ones you keep from the default set.

SubstringSearch

SubstringSearch(options?: BaseAlgorithmOptions): SubstringSearchAlgorithm;

Plain String.prototype.indexOf against every entry. Confidence is how much of the candidate the query covers (needle.length / haystack.length), so searching "pro" scores "Pro" at 1 and "MacBook Pro 16" at 0.21. Reports position, the offset of the hit.

PrefixSearch

PrefixSearch(options?: BaseAlgorithmOptions): PrefixSearchAlgorithm;

Matches entries that begin with the query, the algorithm behind type-ahead boxes. A hit in the middle of an entry does not count. Confidence is how much of the candidate the prefix covers; position is always 0.

KMP

KMP(options?: BaseAlgorithmOptions): KMPAlgorithm;

Knuth–Morris–Pratt substring search: O(n + m) per entry with no backtracking over the candidate, which pays off on long entries and repetitive patterns where naive indexOf degrades. The failure table is built once per query and reused across the whole dataset. Same confidence and position semantics as SubstringSearch.

Also exports the building blocks directly: buildFailureTable(pattern) and kmpIndexOf(haystack, needle, table).

BoyerMoore

BoyerMoore(options?: BaseAlgorithmOptions): BoyerMooreAlgorithm;

Boyer–Moore–Horspool substring search: compares right-to-left and skips ahead on a mismatch, which is sublinear in the happy case because a mismatch can skip a whole pattern length. Good on long entries with a varied alphabet; KMP is the safer bet on short, highly repetitive text. The skip table is built once per query and reused across the dataset. Same confidence and position semantics as SubstringSearch.

Also exports buildBadCharacterTable(pattern) and horspoolIndexOf(haystack, needle, table).

Levenshtein

Levenshtein(options?: LevenshteinOptions): LevenshteinAlgorithm;

type LevenshteinOptions = BaseAlgorithmOptions & {
	maxDistance?: number; // unset by default
};

Fuzzy whole-string match by edit distance: the number of insertions, deletions and substitutions needed to turn one string into the other. The one that catches typos. Confidence is 1 - distance / longestLength, so "iphone" against "iphonw" scores 0.83. Default threshold 0.7; lower it to catch sloppier input, raise it to cut false positives. maxDistance rejects a candidate outright once it needs more than that many edits, regardless of what the confidence formula would have scored it.

Also exports levenshteinDistance(a, b).

JaroWinkler

JaroWinkler(options?: JaroWinklerOptions): JaroWinklerAlgorithm;

type JaroWinklerOptions = BaseAlgorithmOptions & {
	scalingFactor?: number;   // 0.1 by default
	boostThreshold?: number;  // 0.7 by default
};

Jaro similarity plus a bonus for a shared prefix, tuned for short strings with transposed characters, which makes it stronger than Levenshtein on names, SKUs and model codes. Default threshold 0.8. scalingFactor weights how much the prefix bonus is worth; boostThreshold is the Jaro score below which no prefix bonus applies at all.

Also exports jaroSimilarity(a, b) and jaroWinklerSimilarity(a, b, scalingFactor?, boostThreshold?, maxPrefix?).

NgramSearch

NgramSearch(options?: NgramSearchOptions): NgramSearchAlgorithm;

type NgramSearchOptions = BaseAlgorithmOptions & {
	size?: number; // 3 (trigrams) by default
};

Compares bags of overlapping character n-grams with the Sørensen–Dice coefficient: 2 × shared / (|a| + |b|). Order-insensitive and forgiving of word shuffles and inserted noise, which is where edit distance struggles — "pro macbook 16" still scores well against "MacBook Pro 16" even though Levenshtein rejects it outright. Default threshold 0.4. size sets the gram length; 2 for bigrams, 4 for four-grams, and so on.

Also exports toNgrams(value, size) and diceCoefficient(a, b).

SoundexSearch

SoundexSearch(options?: SoundexOptions): SoundexAlgorithm;

type SoundexOptions = BaseAlgorithmOptions & {
	matchTokens?: boolean; // true by default
};

Phonetic matching using the classic Soundex code: an initial letter plus three digits, so "Robert" and "Rupert" both encode to R163. Catches misspellings edit distance misses, at the cost of collapsing genuinely different words that happen to share a code. Whole-string code equality scores 1. With matchTokens (on by default), a single word inside a longer candidate that sounds like the query also matches, scoring 0.75 and reporting that word’s position; set it to false to require the whole candidate to match phonetically.

Also exports soundex(value), which returns "" for input with no letters.

FuzzySubsequence

FuzzySubsequence(options?: FuzzySubsequenceOptions): FuzzySubsequenceAlgorithm;

type FuzzySubsequenceOptions = BaseAlgorithmOptions & {
	compactnessWeight?: number; // 0.7 by default
};

Subsequence matching in the style of an editor’s command palette: every character of the query must appear in the candidate, in order, but not necessarily adjacent; "mbp" finds "MacBook Pro". Confidence blends how tightly the matched characters cluster (compactnessWeight) with how much of the candidate they cover (1 - compactnessWeight), so an exact match scores 1 and a scattered one scores low. Default threshold 0.2, deliberately permissive since initialisms are short and their candidates long.

Scoring helpers without the pipeline

Every helper above is also exported standalone, for scoring one pair of strings without building a Search:

levenshteinDistance, jaroSimilarity, jaroWinklerSimilarity, soundex,
diceCoefficient, toNgrams, kmpIndexOf, buildFailureTable, horspoolIndexOf,
buildBadCharacterTable, buildAmbiguityMap, foldAmbiguous