{"id":13515178,"url":"https://github.com/leeoniya/uFuzzy","last_synced_at":"2025-03-31T04:36:39.598Z","repository":{"id":59983723,"uuid":"537303562","full_name":"leeoniya/uFuzzy","owner":"leeoniya","description":"A tiny, efficient fuzzy search that doesn't suck","archived":false,"fork":false,"pushed_at":"2024-10-21T18:42:46.000Z","size":2094,"stargazers_count":2638,"open_issues_count":9,"forks_count":47,"subscribers_count":12,"default_branch":"main","last_synced_at":"2024-10-29T15:10:34.348Z","etag":null,"topics":["autocomplete","filter-list","fuzzy-matching","fuzzy-search","ranking-algorithm","search","typeahead","typeahead-search"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leeoniya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-16T04:24:29.000Z","updated_at":"2024-10-29T13:39:25.000Z","dependencies_parsed_at":"2023-10-01T09:42:09.458Z","dependency_job_id":"9fe43418-151e-4b35-b395-3f4c041c8bfb","html_url":"https://github.com/leeoniya/uFuzzy","commit_stats":{"total_commits":236,"total_committers":5,"mean_commits":47.2,"dds":"0.021186440677966156","last_synced_commit":"6bb27a8d8c41e4be5458844afc5c89f6c2399512"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeoniya%2FuFuzzy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeoniya%2FuFuzzy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeoniya%2FuFuzzy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeoniya%2FuFuzzy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leeoniya","download_url":"https://codeload.github.com/leeoniya/uFuzzy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246418658,"owners_count":20773934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autocomplete","filter-list","fuzzy-matching","fuzzy-search","ranking-algorithm","search","typeahead","typeahead-search"],"created_at":"2024-08-01T05:01:07.169Z","updated_at":"2025-03-31T04:36:34.583Z","avatar_url":"https://github.com/leeoniya.png","language":"JavaScript","readme":"## ▒ μFuzzy\n\nA tiny, efficient fuzzy search that doesn't suck.\nThis is my fuzzy 🐈. [There are many like it](#a-biased-appraisal-of-similar-work), but this one is mine.[¹](https://en.wikipedia.org/wiki/Rifleman's_Creed#Current_text)\n\n---\n### Overview\n\nuFuzzy is a [fuzzy search](https://en.wikipedia.org/wiki/Approximate_string_matching) library designed to match a relatively short search phrase (needle) against a large list of short-to-medium phrases (haystack).\nIt might be best described as a more forgiving [String.includes()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes).\nCommon applications include list filtering, auto-complete/suggest, and searches for titles, names, descriptions, filenames, and functions.\n\nIn uFuzzy's default `MultiInsert` mode, each match must contain all alpha-numeric characters from the needle in the same sequence;\nin `SingleError` mode, single typos are tolerated in each term ([Damerau–Levenshtein distance](https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance) = 1).\nIts `.search()` API can efficiently [match out-of-order terms](https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026outOfOrder\u0026search=spac%20ca), supports multiple substring exclusions (e.g. `fruit -green -melon`), and exact terms with non-alphanum chars (e.g. `\"C++\"`, `\"$100\"`, `\"#hashtag\"`).\nWhen held _just right_, it can efficiently match against multiple object properties, too.\n\n---\n### Features\n\n- **Junk-free, high quality results** with any dataset. No need to fine-tune indexing options or boosting params to attain some arbitrary relevance score cut-off.\n- **Precise fuzziness control** that follows straightforward rules, without returning unexpected matches.\n- **Sorting you can reason about** and customize using a simple `Array.sort()` which gets access to each match's stats/counters. There's no composite, black box \"score\" to understand.\n- **Concise set of options** that don't interact in mysterious ways to drastically alter combined behavior.\n- **Fast with low resource usage** - there's no index to build, so startup is below 1ms with near-zero memory overhead. Searching a three-term phrase in a 162,000 phrase dataset takes 5ms with out-of-order terms.\n- **Micro, with zero dependencies** - currently [~7.5KB min](https://github.com/leeoniya/uFuzzy/blob/main/dist/uFuzzy.iife.min.js)\n\n[![uFuzzy demo](uFuzzy.png)](https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026outOfOrder\u0026search=spac%20ca)\n\n---\n### Charsets, Alphabets, Diacritics\n\nuFuzzy is optimized for the [Latin/Roman alphabet](https://en.wikipedia.org/wiki/Latin_alphabet) and relies internally on non-unicode regular expressions.\n\nSupport for more languages works by augmenting the built-in Latin regexps with additional chars or by using the slower, universal `{unicode: true}` variant.\nA more simple, but less flexible `{alpha: \"...\"}` alternative replaces the `A-Z` and `a-z` parts of the built-in Latin regexps with chars of your choice (the letter case will be matched automatically during replacement).\n\nThe `uFuzzy.latinize()` util function may be used to strip common accents/diacritics from the haystack and needle prior to searching.\n\n```js\n// Latin (default)\nlet opts = { alpha: \"a-z\" };\n// OR\nlet opts = {\n  // case-sensitive regexps\n  interSplit: \"[^A-Za-z\\\\d']+\",\n  intraSplit: \"[a-z][A-Z]\",\n  intraBound: \"[A-Za-z]\\\\d|\\\\d[A-Za-z]|[a-z][A-Z]\",\n  // case-insensitive regexps\n  intraChars: \"[a-z\\\\d']\",\n  intraContr: \"'[a-z]{1,2}\\\\b\",\n};\n\n// Latin + Norwegian\nlet opts = { alpha: \"a-zæøå\" };\n// OR\nlet opts = {\n  interSplit: \"[^A-Za-zæøåÆØÅ\\\\d']+\",\n  intraSplit: \"[a-zæøå][A-ZÆØÅ]\",\n  intraBound: \"[A-Za-zæøåÆØÅ]\\\\d|\\\\d[A-Za-zæøåÆØÅ]|[a-zæøå][A-ZÆØÅ]\",\n  intraChars: \"[a-zæøå\\\\d']\",\n  intraContr: \"'[a-zæøå]{1,2}\\\\b\",\n};\n\n// Latin + Russian\nlet opts = { alpha: \"a-zа-яё\" };\n// OR\nlet opts = {\n  interSplit: \"[^A-Za-zА-ЯЁа-яё\\\\d']+\",\n  intraSplit: \"[a-z][A-Z]|[а-яё][А-ЯЁ]\",\n  intraBound: \"[A-Za-zА-ЯЁа-яё]\\\\d|\\\\d[A-Za-zА-ЯЁа-яё]|[a-z][A-Z]|[а-яё][А-ЯЁ]\",\n  intraChars: \"[a-zа-яё\\\\d']\",\n  intraContr: \"'[a-z]{1,2}\\\\b\",\n};\n\n// Unicode / universal (50%-75% slower)\nlet opts = {\n  unicode: true,\n  interSplit: \"[^\\\\p{L}\\\\d']+\",\n  intraSplit: \"\\\\p{Ll}\\\\p{Lu}\",\n  intraBound: \"\\\\p{L}\\\\d|\\\\d\\\\p{L}|\\\\p{Ll}\\\\p{Lu}\",\n  intraChars: \"[\\\\p{L}\\\\d']\",\n  intraContr: \"'\\\\p{L}{1,2}\\\\b\",\n};\n```\n\nAll searches are currently case-insensitive; it is not possible to do a case-sensitive search.\n\n---\n### Demos\n\n**NOTE:** The [testdata.json](https://github.com/leeoniya/uFuzzy/blob/main/demos/testdata.json) file is a diverse 162,000 string/phrase dataset 4MB in size, so first load may be slow due to network transfer.\nTry refreshing once it's been cached by your browser.\n\nFirst, uFuzzy in isolation to demonstrate its performance.\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026search=super%20ma\n\nNow the same comparison page, booted with [fuzzysort](https://github.com/farzher/fuzzysort), [QuickScore](https://fwextensions.github.io/quick-score-demo/), and [Fuse.js](https://fusejs.io/):\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy,fuzzysort,QuickScore,Fuse\u0026search=super%20ma\n\nHere is the full library list but with a reduced dataset (just `hearthstone_750`, `urls_and_titles_600`) to avoid crashing your browser:\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?lists=hearthstone_750,urls_and_titles_600\u0026search=moo\n\n---\n### Questions?\n\nAnswers:\n\n- https://news.ycombinator.com/item?id=33035580\n- https://old.reddit.com/r/javascript/comments/xtrszc/ufuzzyjs_a_tiny_efficient_fuzzy_search_that/\n\nElse: https://github.com/leeoniya/uFuzzy/issues\n\n---\n### Installation\n\n### Node\n\n```\nnpm i @leeoniya/ufuzzy\n```\n\n```js\nconst uFuzzy = require('@leeoniya/ufuzzy');\n```\n\n### Browser\n\n```js\n\u003cscript src=\"./dist/uFuzzy.iife.min.js\"\u003e\u003c/script\u003e\n```\n\n---\n### Example\n\n```js\nlet haystack = [\n    'puzzle',\n    'Super Awesome Thing (now with stuff!)',\n    'FileName.js',\n    '/feeding/the/catPic.jpg',\n];\n\nlet needle = 'feed cat';\n\nlet opts = {};\n\nlet uf = new uFuzzy(opts);\n\n// pre-filter\nlet idxs = uf.filter(haystack, needle);\n\n// idxs can be null when the needle is non-searchable (has no alpha-numeric chars)\nif (idxs != null \u0026\u0026 idxs.length \u003e 0) {\n  // sort/rank only when \u003c= 1,000 items\n  let infoThresh = 1e3;\n\n  if (idxs.length \u003c= infoThresh) {\n    let info = uf.info(idxs, haystack, needle);\n\n    // order is a double-indirection array (a re-order of the passed-in idxs)\n    // this allows corresponding info to be grabbed directly by idx, if needed\n    let order = uf.sort(info, haystack, needle);\n\n    // render post-filtered \u0026 ordered matches\n    for (let i = 0; i \u003c order.length; i++) {\n      // using info.idx here instead of idxs because uf.info() may have\n      // further reduced the initial idxs based on prefix/suffix rules\n      console.log(haystack[info.idx[order[i]]]);\n    }\n  }\n  else {\n    // render pre-filtered but unordered matches\n    for (let i = 0; i \u003c idxs.length; i++) {\n      console.log(haystack[idxs[i]]);\n    }\n  }\n}\n```\n\n---\n### Integrated Search\n\nuFuzzy provides a `uf.search(haystack, needle, outOfOrder = 0, infoThresh = 1e3) =\u003e [idxs, info, order]` wrapper which combines the `filter`, `info`, `sort` steps above.\nThis method also implements efficient logic for matching search terms out of order and support for multiple substring exclusions, e.g. `fruit -green -melon`.\n\n---\n### Match Highlighting\n\nGet your ordered matches first:\n\n```js\nlet haystack = [\n  'foo',\n  'bar',\n  'cowbaz',\n];\n\nlet needle = 'ba';\n\nlet u = new uFuzzy();\n\nlet idxs = u.filter(haystack, needle);\nlet info = u.info(idxs, haystack, needle);\nlet order = u.sort(info, haystack, needle);\n```\n\nBasic innerHTML highlighter (`\u003cmark\u003e`-wrapped ranges):\n\n```js\nlet innerHTML = '';\n\nfor (let i = 0; i \u003c order.length; i++) {\n  let infoIdx = order[i];\n\n  innerHTML += uFuzzy.highlight(\n    haystack[info.idx[infoIdx]],\n    info.ranges[infoIdx],\n  ) + '\u003cbr\u003e';\n}\n\nconsole.log(innerHTML);\n```\n\ninnerHTML highlighter with custom marking function (`\u003cb\u003e`-wrapped ranges):\n\n```js\nlet innerHTML = '';\n\nconst mark = (part, matched) =\u003e matched ? '\u003cb\u003e' + part + '\u003c/b\u003e' : part;\n\nfor (let i = 0; i \u003c order.length; i++) {\n  let infoIdx = order[i];\n\n  innerHTML += uFuzzy.highlight(\n    haystack[info.idx[infoIdx]],\n    info.ranges[infoIdx],\n\n    mark,\n  ) + '\u003cbr\u003e';\n}\n\nconsole.log(innerHTML);\n```\n\nDOM/JSX element highlighter with custom marking and append functions:\n\n```js\nlet domElems = [];\n\nconst mark = (part, matched) =\u003e {\n  let el = matched ? document.createElement('mark') : document.createElement('span');\n  el.textContent = part;\n  return el;\n};\n\nconst append = (accum, part) =\u003e { accum.push(part); };\n\nfor (let i = 0; i \u003c order.length; i++) {\n  let infoIdx = order[i];\n\n  let matchEl = document.createElement('div');\n\n  let parts = uFuzzy.highlight(\n    haystack[info.idx[infoIdx]],\n    info.ranges[infoIdx],\n\n    mark,\n    [],\n    append,\n  );\n\n  matchEl.append(...parts);\n\n  domElems.push(matchEl);\n}\n\ndocument.getElementById('matches').append(...domElems);\n```\n\n---\n### How It Works\n\nuFuzzy has two operational modes which differ in matching strategy:\n\n- **intraMode: 0** (default) requires all alpha-numeric characters in each search term to exist in the same sequence in all matches. For example, when searching for \"**cat**\", this mode is capable of matching the strings below. What is _actually_ matched will depend on additonal fuzziness settings.\n  - **cat**\n  - **c**o**at**\n  - s**c**r**at**ch\n  - **ca**n**t**ina\n  - tra**c**tors **a**re la**t**e\n- **intraMode: 1** allows for a single error in each term of the search phrase, where an error is one of: substitution (replacement), transposition (swap), insertion (addition), or deletion (omission). The search strings with errors below can return matches containing \"**example**\". What is _actually_ matched will depend on additonal fuzziness settings. In contrast to the previous mode, searching for \"**example**\" will never match \"**ex**tr**a** **m**a**ple**\".\n  - `example` - exact\n  - `examplle` - single insertion (addition)\n  - `exemple` - single substitution (replacement)\n  - `exmaple` - single transposition (swap)\n  - `exmple` - single deletion (omission)\n  - `xamp` - partial\n  - `xmap` - partial with transposition\n\nThere are 3 phases to a search:\n\n1. **Filter** filters the full `haystack` with a fast RegExp compiled from your `needle` without doing any extra ops. It returns an array of matched indices in original order.\n2. **Info** collects more detailed stats about the filtered matches, such as start offsets, fuzz level, prefix/suffix counters, etc. It also gathers substring match positions for range highlighting. Finally, it filters out any matches that don't conform to the desired prefix/suffix rules. To do all this it re-compiles the `needle` into two more-expensive RegExps that can partition each match. Therefore, it should be run on a reduced subset of the haystack, usually returned by the Filter phase. The [uFuzzy demo](https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy) is gated at \u003c= 1,000 filtered items, before moving ahead with this phase.\n3. **Sort** does an `Array.sort()` to determine final result order, utilizing the `info` object returned from the previous phase. A custom sort function can be provided via a uFuzzy option: `{sort: (info, haystack, needle) =\u003e idxsOrder}`.\n\n---\n### API\n\nA liberally-commented 200 LoC [uFuzzy.d.ts](https://github.com/leeoniya/uFuzzy/blob/main/dist/uFuzzy.d.ts) file.\n\n---\n### Options\n\nOptions with an **inter** prefix apply to allowances _in between_ search terms, while those with an **intra** prefix apply to allowances _within_ each search term.\n\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth\u003eOption\u003c/th\u003e\n            \u003cth\u003eDescription\u003c/th\u003e\n            \u003cth\u003eDefault\u003c/th\u003e\n            \u003cth\u003eExamples\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003eintraMode\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eHow term matching should be performed\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e0\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                \u003ccode\u003e0\u003c/code\u003e MultiInsert\u003cbr\u003e\n                \u003ccode\u003e1\u003c/code\u003e SingleError\u003cbr\u003e\u003cbr\u003e\n                See \u003ca href=\"#how-it-works\"\u003eHow It Works\u003c/a\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003eintraIns\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eMax number of extra chars allowed\u003cbr\u003ebetween each char within a term\u003c/td\u003e\n            \u003ctd\u003eMatches the value of \u003ccode\u003eintraMode\u003c/code\u003e (either \u003ccode\u003e0\u003c/code\u003e or \u003ccode\u003e1\u003c/code\u003e)\u003c/td\u003e\n            \u003ctd\u003e\n                Searching \"cat\"...\u003cbr\u003e\n                \u003ccode\u003e0\u003c/code\u003e can match: \u003cb\u003ecat\u003c/b\u003e, s\u003cb\u003ecat\u003c/b\u003e, \u003cb\u003ecat\u003c/b\u003ech, va\u003cb\u003ecat\u003c/b\u003ee\u003cbr\u003e\n                \u003ccode\u003e1\u003c/code\u003e also matches: \u003cb\u003eca\u003c/b\u003er\u003cb\u003et\u003c/b\u003e, \u003cb\u003ec\u003c/b\u003eh\u003cb\u003ea\u003c/b\u003ep\u003cb\u003et\u003c/b\u003eer, out\u003cb\u003eca\u003c/b\u003es\u003cb\u003et\u003c/b\u003e\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003einterIns\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eMax number of extra chars allowed between terms\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003eInfinity\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                Searching \"where is\"...\u003cbr\u003e\n                \u003ccode\u003eInfinity\u003c/code\u003e can match: \u003cb\u003ewhere is\u003c/b\u003e, \u003cb\u003ewhere\u003c/b\u003e have blah w\u003cb\u003eis\u003c/b\u003edom\u003cbr\u003e\n                \u003ccode\u003e5\u003c/code\u003e cannot match: where have blah wisdom\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ccode\u003eintraSub\u003c/code\u003e\u003cbr\u003e\n                \u003ccode\u003eintraTrn\u003c/code\u003e\u003cbr\u003e\n                \u003ccode\u003eintraDel\u003c/code\u003e\u003cbr\u003e\n            \u003c/td\u003e\n            \u003ctd\u003e\n                For \u003ccode\u003eintraMode: 1\u003c/code\u003e only,\u003cbr\u003e\n                Error types to tolerate within terms\n            \u003c/td\u003e\n            \u003ctd\u003eMatches the value of \u003ccode\u003eintraMode\u003c/code\u003e (either \u003ccode\u003e0\u003c/code\u003e or \u003ccode\u003e1\u003c/code\u003e)\u003c/td\u003e\n            \u003ctd\u003e\n                \u003ccode\u003e0\u003c/code\u003e No\u003cbr\u003e\n                \u003ccode\u003e1\u003c/code\u003e Yes\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003eintraChars\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003ePartial regexp for allowed insert\u003cbr\u003echars between each char within a term\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e[a-z\\d']\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                \u003ccode\u003e[a-z\\d]\u003c/code\u003e matches only alpha-numeric (case-insensitive)\u003cbr\u003e\n                \u003ccode\u003e[\\w-]\u003c/code\u003e would match alpha-numeric, undercore, and hyphen\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003eintraFilt\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eCallback for excluding results based on term \u0026amp; match\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e(term, match, index) =\u003e true\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                Do your own thing, maybe...\n                - Length diff threshold\u003cbr\u003e\n                - Levenshtein distance\u003cbr\u003e\n                - Term offset or content\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003einterChars\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003ePartial regexp for allowed chars between terms\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e.\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                \u003ccode\u003e.\u003c/code\u003e matches all chars\u003cbr\u003e\n                \u003ccode\u003e[^a-z\\d]\u003c/code\u003e would only match whitespace and punctuation\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003einterLft\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eDetermines allowable term left boundary\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e0\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                Searching \"mania\"...\u003cbr\u003e\n                \u003ccode\u003e0\u003c/code\u003e any - anywhere: ro\u003cb\u003emania\u003c/b\u003en\u003cbr\u003e\n                \u003ccode\u003e1\u003c/code\u003e loose - whitespace, punctuation, alpha-num, case-change transitions: Track\u003cb\u003eMania\u003c/b\u003e, \u003cb\u003emania\u003c/b\u003ec\u003cbr\u003e\n                \u003ccode\u003e2\u003c/code\u003e strict - whitespace, punctuation: \u003cb\u003emania\u003c/b\u003ecally\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003einterRgt\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eDetermines allowable term right boundary\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e0\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                Searching \"mania\"...\u003cbr\u003e\n                \u003ccode\u003e0\u003c/code\u003e any - anywhere: ro\u003cb\u003emania\u003c/b\u003en\u003cbr\u003e\n                \u003ccode\u003e1\u003c/code\u003e loose - whitespace, punctuation, alpha-num, case-change transitions: \u003cb\u003eMania\u003c/b\u003eStar\u003cbr\u003e\n                \u003ccode\u003e2\u003c/code\u003e strict - whitespace, punctuation: \u003cb\u003emania\u003c/b\u003e_foo\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\u003ccode\u003esort\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003eCustom result sorting function\u003c/td\u003e\n            \u003ctd\u003e\u003ccode\u003e(info, haystack, needle) =\u003e idxsOrder\u003c/code\u003e\u003c/td\u003e\n            \u003ctd\u003e\n                Default: \u003ca href=\"https://github.com/leeoniya/uFuzzy/blob/bba02537334ae9d02440b86262fbfa40d86daa54/src/uFuzzy.js#L32-L52\"\u003eSearch sort\u003c/a\u003e, prioritizes full term matches and char density\u003cbr\u003e\n                Demo: \u003ca href=\"https://github.com/leeoniya/uFuzzy/blob/bba02537334ae9d02440b86262fbfa40d86daa54/demos/compare.html#L264-L288\"\u003eTypeahead sort\u003c/a\u003e, prioritizes start offset and match length\u003cbr\u003e\n            \u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n---\n### A biased appraisal of similar work\n\nThis assessment is extremely narrow and, of course, biased towards my use cases, text corpus, and my complete expertise in operating my own library.\nIt is highly probable that I'm not taking full advantage of some feature in other libraries that may significantly improve outcomes along some axis;\nI welcome improvement PRs from anyone with deeper library knowledge than afforded by my hasty 10min skim over any \"Basic usage\" example and README doc.\n\n#### Search quality\n\nCan-of-worms #1.\n\nBefore we discuss [performance](#performance) let's talk about search quality, because speed is irrelevant when your results are a strange medly of \"Oh yeah!\" and \"WTF?\".\n\nSearch quality is very subjective.\nWhat constitutes a good top match in a \"typeahead / auto-suggest\" case can be a poor match in a \"search / find-all\" scenario.\nSome solutions optimize for the latter, some for the former.\nIt's common to find knobs that skew the results in either direction, but these are often by-feel and imperfect, being little more than a proxy to producing a single, composite match \"score\".\n\n**UPDATE (2024):** The critique below regarding bizzare matches is only true for the *default* config of Fuse.js.\nCounterintuitively, [setting `ignoreFieldNorm: true`](https://github.com/krisk/Fuse/issues/753#issuecomment-1871416557) improved the results considerably, but ordering of the high quality matches remains ungreat.\n\nLet's take a look at some matches produced by the most popular fuzzy search library, [Fuse.js](https://github.com/krisk/Fuse) and some others for which match highlighting is implemented in the demo.\n\nSearching for the partial term **\"twili\"**, we see these results appearing above numerous obvious **\"twilight\"** results:\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy,fuzzysort,QuickScore,Fuse\u0026search=twili\n\n- **twi**r**li**ng\n- **T**he total number of received alerts that **w**ere **i**nva**li**d.\n- **T**om Clancy's Ghost Recon **Wil**dlands - AS**I**A Pre-order Standard Uplay Activation\n- **t**heHunter™: Call of the **Wi**ld - Bearclaw **Li**te CB-60\n\nNot only are these poor matches in isolation, but they actually rank higher than literal substrings.\n\nFinishing the search term to **\"twilight\"**, _still_ scores bizzare results higher:\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy,fuzzysort,QuickScore,Fuse\u0026search=twilight\n\n- Magic: **T**he Gathering - Duels of the Planeswalkers **Wi**ngs of **Light** Unlock\n- **T**he **Wil**d E**ight**\n\nSome engines do better with partial prefix matches, at the expense of higher startup/indexing cost:\n\nhttps://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy,FlexSearch,match-sorter,MiniSearch\u0026search=twili\n\nHere, `match-sorter` returns 1,384 results, but only the first 40 are relevant. How do we know where the cut-off is?\n\n\u003c!--\ntwil  0.1683 ok, 0.25+ bad\nchest 0.1959 ok, 0.2+ bad\ntrain\nnin tur\npuzz, puzl (MiniSearch, {fuzzy: 0.4}, uFuzzy, intraIns: 1)\n--\u003e\n\n#### Performance\n\nCan-of-worms #2.\n\nAll benchmarks suck, but this one might suck more than others.\n\n- I've tried to follow any \"best performance\" advice when I could find it in each library's docs, but it's a certainty that some stones were left unturned when implementing ~20 different search engines.\n- Despite my best efforts, result quality is still extremely variable between libraries, and even between search terms. In some cases, results are very poor but the library is very fast; in other cases, the results are better, but the library is quite slow. What use is extreme speed when the search quality is sub-par? This is a subjective, nuanced topic that will surely affect how you interpret these numbers. I consider uFuzzy's search quality second-to-none, so my view of most faster libraries is typically one of quality trade-offs I'm happy not to have made. I encourage you to evaluate the results for all benched search phrases manually to decide this for yourself.\n- Many fulltext \u0026 document-search libraries compared here are designed to work best with exact terms rather than partial matches (which this benchmark is skewed towards).\n\nStill, something is better than a hand-wavy YMMV/do-it-yourself dismissal and certainly better than nothing.\n\n#### Benchmark\n\n**Environment**\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eDate\u003c/th\u003e\n    \u003ctd\u003e2023-10\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003eHardware\u003c/th\u003e\n    \u003ctd\u003e\n      CPU: \u003ca href=\"https://www.amd.com/en/products/apu/amd-ryzen-7-pro-5850u\"\u003eRyzen 7 PRO 5850U\u003c/a\u003e (1.9GHz, 7nm, 15W TDP)\u003cbr\u003e\n      RAM: 48GB\u003cbr\u003e\n      SSD: Samsung SSD 980 PRO 1TB (NVMe)\u003cbr\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003eOS\u003c/th\u003e\n    \u003ctd\u003eEndeavourOS (Arch Linux)\u003cbr\u003ev6.5.4-arch2-1 x86_64\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003eChrome\u003c/th\u003e\n    \u003ctd\u003ev117.0.5938.132\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n- Each benchmark can be run by changing the `libs` parameter to the desired library name: https://leeoniya.github.io/uFuzzy/demos/compare.html?bench\u0026libs=uFuzzy\n- Results output is suppressed in `bench` mode to avoid benchmarking the DOM.\n- Measurements are taken in the Performance secrion of Chrome's DevTools by recording several reloads of the bench page, with forced garbage collection in between. The middle/typical run is used to collect numbers.\n- The search corpus is 162,000 words and phrases, loaded from a 4MB [testdata.json](https://github.com/leeoniya/uFuzzy/blob/main/demos/testdata.json).\n- The benchmark types and then deletes, character-by-character (every 20ms) the following search terms, triggering a search for each keypress: `test`, `chest`, `super ma`, `mania`, `puzz`, `prom rem stor`, `twil`.\n\nTo evaluate the results for each library, or to compare several, simply visit the same page with more `libs` and without `bench`: https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy,fuzzysort,QuickScore,Fuse\u0026search=super%20ma.\n\n![profile example](bench.png)\n\nThere are several metrics evaluated:\n\n- Init time - how long it takes to load the library and build any required index to perform searching.\n- Bench runtime - how long it takes to execute all searches.\n- Memory required - peak JS heap size used during the bench as well as how much is still retained after a forced garbage collection at the end.\n- GC cost - how much time is needed to collect garbage at the end (main thread jank)\n\n\u003c!--\nhttps://bestofjs.org/projects?tags=search\n--\u003e\n\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth\u003eLib\u003c/th\u003e\n            \u003cth\u003eStars\u003c/th\u003e\n            \u003cth\u003eSize (min)\u003c/th\u003e\n            \u003cth\u003eInit\u003c/th\u003e\n            \u003cth\u003eSearch\u003cbr\u003e(x 86)\u003c/th\u003e\n            \u003cth\u003eHeap (peak)\u003c/th\u003e\n            \u003cth\u003eRetained\u003c/th\u003e\n            \u003cth\u003eGC\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/leeoniya/uFuzzy\"\u003euFuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 2.3k\u003c/td\u003e\n            \u003ctd\u003e7.6KB\u003c/td\u003e\n            \u003ctd\u003e0.5ms\u003c/td\u003e\n            \u003ctd\u003e434ms\u003c/td\u003e\n            \u003ctd\u003e28.4MB\u003c/td\u003e\n            \u003ctd\u003e7.4MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/leeoniya/uFuzzy\"\u003euFuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026prefixCache\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\u003cbr\u003e\n                (external prefix caching)\n            \u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e210ms\u003c/td\u003e\n            \u003ctd\u003e27.8MB\u003c/td\u003e\n            \u003ctd\u003e7.4MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/leeoniya/uFuzzy\"\u003euFuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026intraIns=1\u0026intraChars=[a-z\\d%27%20]\u0026outOfOrder\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\u003cbr\u003e\n                (outOfOrder, fuzzier)\n            \u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e545ms\u003c/td\u003e\n            \u003ctd\u003e29.5MB\u003c/td\u003e\n            \u003ctd\u003e7.4MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/leeoniya/uFuzzy\"\u003euFuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=uFuzzy\u0026intraMode=1\u0026intraIns=1\u0026intraChars=[a-z\\d%27%20]\u0026outOfOrder\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\u003cbr\u003e\n                (outOfOrder, fuzzier, SingleError)\n            \u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e\u003c/td\u003e\n            \u003ctd\u003e508ms\u003c/td\u003e\n            \u003ctd\u003e30.0MB\u003c/td\u003e\n            \u003ctd\u003e7.4MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003cth colspan=\"8\"\u003e-------\u003c/th\u003e\n        \u003c/th\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/krisk/Fuse\"\u003eFuse.js\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Fuse\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 16.6k\u003c/td\u003e\n            \u003ctd\u003e24.2KB\u003c/td\u003e\n            \u003ctd\u003e31ms\u003c/td\u003e\n            \u003ctd\u003e33875ms\u003c/td\u003e\n            \u003ctd\u003e245MB\u003c/td\u003e\n            \u003ctd\u003e13.9MB\u003c/td\u003e\n            \u003ctd\u003e25ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/nextapps-de/flexsearch\"\u003eFlexSearch (Light)\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=FlexSearch\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 10.7k\u003c/td\u003e\n            \u003ctd\u003e6.2KB\u003c/td\u003e\n            \u003ctd\u003e3210ms\u003c/td\u003e\n            \u003ctd\u003e83ms\u003c/td\u003e\n            \u003ctd\u003e670MB\u003c/td\u003e\n            \u003ctd\u003e316MB\u003c/td\u003e\n            \u003ctd\u003e553ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/olivernn/lunr.js\"\u003eLunr.js\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Lunr\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 8.7k\u003c/td\u003e\n            \u003ctd\u003e29.4KB\u003c/td\u003e\n            \u003ctd\u003e1704ms\u003c/td\u003e\n            \u003ctd\u003e996ms\u003c/td\u003e\n            \u003ctd\u003e380MB\u003c/td\u003e\n            \u003ctd\u003e123MB\u003c/td\u003e\n            \u003ctd\u003e166ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/oramasearch/orama\"\u003eOrama (formerly Lyra)\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Orama\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 6.4k\u003c/td\u003e\n            \u003ctd\u003e41.5KB\u003c/td\u003e\n            \u003ctd\u003e2650ms\u003c/td\u003e\n            \u003ctd\u003e225ms\u003c/td\u003e\n            \u003ctd\u003e313MB\u003c/td\u003e\n            \u003ctd\u003e192MB\u003c/td\u003e\n            \u003ctd\u003e180ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/lucaong/minisearch\"\u003eMiniSearch\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=MiniSearch\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 3.4k\u003c/td\u003e\n            \u003ctd\u003e29.1KB\u003c/td\u003e\n            \u003ctd\u003e504ms\u003c/td\u003e\n            \u003ctd\u003e1453ms\u003c/td\u003e\n            \u003ctd\u003e438MB\u003c/td\u003e\n            \u003ctd\u003e67MB\u003c/td\u003e\n            \u003ctd\u003e105ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/kentcdodds/match-sorter\"\u003ematch-sorter\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=match-sorter\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 3.4k\u003c/td\u003e\n            \u003ctd\u003e7.3KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e6245ms\u003c/td\u003e\n            \u003ctd\u003e71MB\u003c/td\u003e\n            \u003ctd\u003e7.3MB\u003c/td\u003e\n            \u003ctd\u003e12ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/farzher/fuzzysort\"\u003efuzzysort\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fuzzysort\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 3.4k\u003c/td\u003e\n            \u003ctd\u003e6.2KB\u003c/td\u003e\n            \u003ctd\u003e50ms\u003c/td\u003e\n            \u003ctd\u003e1321ms\u003c/td\u003e\n            \u003ctd\u003e175MB\u003c/td\u003e\n            \u003ctd\u003e84MB\u003c/td\u003e\n            \u003ctd\u003e63ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/kbrsh/wade\"\u003eWade\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Wade\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 3k\u003c/td\u003e\n            \u003ctd\u003e4KB\u003c/td\u003e\n            \u003ctd\u003e781ms\u003c/td\u003e\n            \u003ctd\u003e194ms\u003c/td\u003e\n            \u003ctd\u003e438MB\u003c/td\u003e\n            \u003ctd\u003e42MB\u003c/td\u003e\n            \u003ctd\u003e130ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/bevacqua/fuzzysearch\"\u003efuzzysearch\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fuzzysearch\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 2.7k\u003c/td\u003e\n            \u003ctd\u003e0.2KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e529ms\u003c/td\u003e\n            \u003ctd\u003e26.2MB\u003c/td\u003e\n            \u003ctd\u003e7.3MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/bvaughn/js-search\"\u003ejs-search\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=js-search\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 2.1k\u003c/td\u003e\n            \u003ctd\u003e17.1KB\u003c/td\u003e\n            \u003ctd\u003e5620ms\u003c/td\u003e\n            \u003ctd\u003e1190ms\u003c/td\u003e\n            \u003ctd\u003e1740MB\u003c/td\u003e\n            \u003ctd\u003e734MB\u003c/td\u003e\n            \u003ctd\u003e2600ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/weixsong/elasticlunr.js\"\u003eElasticlunr.js\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Elasticlunr\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 2k\u003c/td\u003e\n            \u003ctd\u003e18.1KB\u003c/td\u003e\n            \u003ctd\u003e933ms\u003c/td\u003e\n            \u003ctd\u003e1330ms\u003c/td\u003e\n            \u003ctd\u003e196MB\u003c/td\u003e\n            \u003ctd\u003e70MB\u003c/td\u003e\n            \u003ctd\u003e135ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/Glench/fuzzyset.js\"\u003eFuzzyset\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=Fuzzyset\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 1.4k\u003c/td\u003e\n            \u003ctd\u003e2.8KB\u003c/td\u003e\n            \u003ctd\u003e2962ms\u003c/td\u003e\n            \u003ctd\u003e606ms\u003c/td\u003e\n            \u003ctd\u003e654MB\u003c/td\u003e\n            \u003ctd\u003e238MB\u003c/td\u003e\n            \u003ctd\u003e239ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/fergiemcdowall/search-index\"\u003esearch-index\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=search-index\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 1.4k\u003c/td\u003e\n            \u003ctd\u003e168KB\u003c/td\u003e\n            \u003ctd colspan=\"5\"\u003eRangeError: Maximum call stack size exceeded\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/brianreavis/sifter.js\"\u003esifter.js\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=sifter\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 1.1k\u003c/td\u003e\n            \u003ctd\u003e7.5KB\u003c/td\u003e\n            \u003ctd\u003e3ms\u003c/td\u003e\n            \u003ctd\u003e1070ms\u003c/td\u003e\n            \u003ctd\u003e46.2MB\u003c/td\u003e\n            \u003ctd\u003e10.6MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/ajitid/fzf-for-js\"\u003efzf-for-js\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fzf-for-js\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 831\u003c/td\u003e\n            \u003ctd\u003e15.4KB\u003c/td\u003e\n            \u003ctd\u003e50ms\u003c/td\u003e\n            \u003ctd\u003e6290ms\u003c/td\u003e\n            \u003ctd\u003e153MB\u003c/td\u003e\n            \u003ctd\u003e25MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/mattyork/fuzzy\"\u003efuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fuzzy\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 819\u003c/td\u003e\n            \u003ctd\u003e1.4KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e5427ms\u003c/td\u003e\n            \u003ctd\u003e72MB\u003c/td\u003e\n            \u003ctd\u003e7.3MB\u003c/td\u003e\n            \u003ctd\u003e14ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/EthanRutherford/fast-fuzzy\"\u003efast-fuzzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fast-fuzzy\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 346\u003c/td\u003e\n            \u003ctd\u003e18.2KB\u003c/td\u003e\n            \u003ctd\u003e790ms\u003c/td\u003e\n            \u003ctd\u003e19266ms\u003c/td\u003e\n            \u003ctd\u003e550MB\u003c/td\u003e\n            \u003ctd\u003e165MB\u003c/td\u003e\n            \u003ctd\u003e140ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/itemsapi/itemsjs\"\u003eItemsJS\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=ItemsJS\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 305\u003c/td\u003e\n            \u003ctd\u003e109KB\u003c/td\u003e\n            \u003ctd\u003e2400ms\u003c/td\u003e\n            \u003ctd\u003e11304ms\u003c/td\u003e\n            \u003ctd\u003e320MB\u003c/td\u003e\n            \u003ctd\u003e88MB\u003c/td\u003e\n            \u003ctd\u003e163ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/rmm5t/liquidmetal\"\u003eLiquidMetal\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=LiquidMetal\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 292\u003c/td\u003e\n            \u003ctd\u003e4.2KB\u003c/td\u003e\n            \u003ctd colspan=\"5\"\u003e(crash)\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/wouter2203/fuzzy-search\"\u003eFuzzySearch\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=FuzzySearch\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 209\u003c/td\u003e\n            \u003ctd\u003e3.5KB\u003c/td\u003e\n            \u003ctd\u003e2ms\u003c/td\u003e\n            \u003ctd\u003e3948ms\u003c/td\u003e\n            \u003ctd\u003e84MB\u003c/td\u003e\n            \u003ctd\u003e10.5MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/jeancroy/FuzzySearch\"\u003eFuzzySearch2\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=FuzzySearch2\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 186\u003c/td\u003e\n            \u003ctd\u003e19.4KB\u003c/td\u003e\n            \u003ctd\u003e93ms\u003c/td\u003e\n            \u003ctd\u003e4189ms\u003c/td\u003e\n            \u003ctd\u003e117MB\u003c/td\u003e\n            \u003ctd\u003e40.3MB\u003c/td\u003e\n            \u003ctd\u003e40ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/fwextensions/quick-score\"\u003eQuickScore\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=QuickScore\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 153\u003c/td\u003e\n            \u003ctd\u003e9.5KB\u003c/td\u003e\n            \u003ctd\u003e10ms\u003c/td\u003e\n            \u003ctd\u003e6915ms\u003c/td\u003e\n            \u003ctd\u003e133MB\u003c/td\u003e\n            \u003ctd\u003e12.1MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/localvoid/ndx\"\u003endx\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=ndx\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 142\u003c/td\u003e\n            \u003ctd\u003e2.9KB\u003c/td\u003e\n            \u003ctd\u003e300ms\u003c/td\u003e\n            \u003ctd\u003e581ms\u003c/td\u003e\n            \u003ctd\u003e308MB\u003c/td\u003e\n            \u003ctd\u003e137MB\u003c/td\u003e\n            \u003ctd\u003e262ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/jhawthorn/fzy.js/\"\u003efzy\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fzy\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 133\u003c/td\u003e\n            \u003ctd\u003e1.5KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e3932ms\u003c/td\u003e\n            \u003ctd\u003e34MB\u003c/td\u003e\n            \u003ctd\u003e7.3MB\u003c/td\u003e\n            \u003ctd\u003e10ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/axules/fuzzy-tools\"\u003efuzzy-tools\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fuzzy-tools\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 13\u003c/td\u003e\n            \u003ctd\u003e3KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e5138ms\u003c/td\u003e\n            \u003ctd\u003e164MB\u003c/td\u003e\n            \u003ctd\u003e7.5MB\u003c/td\u003e\n            \u003ctd\u003e18ms\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e\n                \u003ca href=\"https://github.com/grafana/grafana/blob/main/packages/grafana-ui/src/utils/fuzzy.ts\"\u003efuzzyMatch\u003c/a\u003e\n                (\u003ca href=\"https://leeoniya.github.io/uFuzzy/demos/compare.html?libs=fuzzyMatch\u0026search=super%20ma\"\u003etry\u003c/a\u003e)\n            \u003c/td\u003e\n            \u003ctd\u003e★ 0\u003c/td\u003e\n            \u003ctd\u003e1KB\u003c/td\u003e\n            \u003ctd\u003e0.1ms\u003c/td\u003e\n            \u003ctd\u003e2415ms\u003c/td\u003e\n            \u003ctd\u003e83.5MB\u003c/td\u003e\n            \u003ctd\u003e7.3MB\u003c/td\u003e\n            \u003ctd\u003e13ms\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n","funding_links":[],"categories":["JavaScript","UI Components"],"sub_categories":["Search"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeoniya%2FuFuzzy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleeoniya%2FuFuzzy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeoniya%2FuFuzzy/lists"}