Skip to content

nivalis-studio/string-similarity

 
 

Repository files navigation

@nivalis/string-similarity

String similarity helpers powered by Dice's coefficient. Use it to rank fuzzy matches, measure duplicate content, or power smart suggestions with predictable, deterministic scoring.

Highlights

  • Modern TypeScript codebase with typed ESM builds
  • Fast O(n) bigram comparison implementation
  • Zero dependencies and side-effect free for optimal tree shaking
  • Works anywhere a JavaScript runtime with ES2020 support is available

Installation

# pick the package manager you prefer
bun add @nivalis/string-similarity
# or
npm install @nivalis/string-similarity
# or
pnpm add @nivalis/string-similarity

The package is ESM-only. Use Node.js 18+, Bun, Deno, or a bundler that understands ESM.

Quick Start

import { compareTwoStrings, findBestMatch } from '@nivalis/string-similarity';

const similarity = compareTwoStrings('healed', 'sealed');
// similarity === 0.8

const { ratings, bestMatch } = findBestMatch('healed', [
  'mailed',
  'sealed',
  'theatre',
]);

/* ratings === [
  { target: 'mailed', rating: 0.4 },
  { target: 'sealed', rating: 0.8 },
  { target: 'theatre', rating: 0.36363636363636365 },
] */
/* bestMatch === { target: 'sealed', rating: 0.8 } */

API

compareTwoStrings(first: string, second: string): number

Returns a score between 0 and 1. Whitespace is stripped before comparison and the order of arguments does not matter. When both inputs are empty or whitespace-only, the score is 1 only if the raw strings are strictly equal, and 0 otherwise (e.g. ' ' vs '\t' scores 0).

  • first / second: Strings with at least two characters for the best signal
  • Returns: number similarity score
compareTwoStrings('french', 'quebec');
// 0
compareTwoStrings('Olive-green table for sale, in extremely good condition.',
  'For sale: table in very good condition, olive green in colour.');
// 0.6060606060606061

findBestMatch(mainString: string, targetStrings: string[])

Evaluates every entry in targetStrings and returns:

  • ratings: ordered array of { target: string, rating: number }
  • bestMatch: the record with the highest rating
  • bestMatchIndex: the index of bestMatch inside targetStrings
const result = findBestMatch('Olive-green table for sale, in extremely good condition.', [
  'For sale: green Subaru Impreza, 210,000 miles',
  'For sale: table in very good condition, olive green in colour.',
  'Wanted: mountain bike with at least 21 gears.',
]);

result.bestMatch.target;
// 'For sale: table in very good condition, olive green in colour.'

Invalid arguments throw an error. Pass a non-empty mainString and a non-empty array of strings.

Algorithm Notes

  • Based on bigram overlap (Dice coefficient) for predictable rankings
  • Ignores whitespace and repeated bigrams to reduce noise
  • Inputs are Unicode-normalized to NFC before comparison, so composed and decomposed forms of the same text (e.g. 'café' in NFC vs NFD) score identically
  • Known limitation: bigrams are formed from UTF-16 code units, so surrogate pairs (emoji and other astral-plane characters) are split across bigrams. Results stay deterministic and symmetric, but scores for emoji-heavy strings are approximate
  • Complexity is O(n) relative to total input length, making it suitable for realtime UI filtering

Development

bun install        # install dependencies
bun test           # run the Bun test suite
bun run lint       # biome static analysis
bun run build      # compile to dist/ via tsdown

Automated hooks are managed by Lefthook. See CONTRIBUTING.md for detailed workflows, branch strategy, and release guidance.

Roadmap

  • Export an async/bulk API that can precompute bigrams for a target list and reuse them across multiple queries, reducing redundant work for search or autocomplete scenarios.

Release Notes

5.0.0

  • Converted the library to TypeScript and ESM-only exports
  • Switched to named exports compareTwoStrings and findBestMatch
  • Removed UMD/browser bundles in favor of modern bundler workflows

License

MIT © Nivalis Studio

About

Finds degree of similarity between two strings, based on Dice's Coefficient, which is mostly better than Levenshtein distance.

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages

  • TypeScript 98.7%
  • JavaScript 1.3%