{"id":18460735,"url":"https://github.com/jou-amjs/sdm2","last_synced_at":"2025-10-11T15:19:32.864Z","repository":{"id":57372382,"uuid":"387197645","full_name":"JOU-amjs/sdm2","owner":"JOU-amjs","description":"A high performance library to match discontinuous strings.","archived":false,"fork":false,"pushed_at":"2023-08-08T04:06:45.000Z","size":94404,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T02:47:56.748Z","etag":null,"topics":["browser","matcher","nodejs","string","string-matching","string-search","strings"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/JOU-amjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-18T14:39:07.000Z","updated_at":"2025-01-21T06:12:07.000Z","dependencies_parsed_at":"2024-11-06T08:40:38.260Z","dependency_job_id":null,"html_url":"https://github.com/JOU-amjs/sdm2","commit_stats":null,"previous_names":["jou-amjs/sdm","jou-amjs/string-discontinuous-match","jou-amjs/sdm2"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JOU-amjs%2Fsdm2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JOU-amjs%2Fsdm2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JOU-amjs%2Fsdm2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JOU-amjs%2Fsdm2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JOU-amjs","download_url":"https://codeload.github.com/JOU-amjs/sdm2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247792058,"owners_count":20996876,"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":["browser","matcher","nodejs","string","string-matching","string-search","strings"],"created_at":"2024-11-06T08:27:55.527Z","updated_at":"2025-10-11T15:19:27.819Z","avatar_url":"https://github.com/JOU-amjs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n   \u003cimg width=\"200px\" src=\"https://github.com/JOU-amjs/sdm2/assets/29848971/0eb41c8d-7021-4128-bba8-13ad08e6c696\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cb\u003eA high-performance string discontinuous search function library\u003c/b\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eEnglish | \u003ca href=\"./README.zh-CN.md\"\u003e📑中文\u003c/a\u003e\u003c/p\u003e\n\n[![npm](https://img.shields.io/npm/v/sdm2)](https://www.npmjs.com/package/sdm2)\n[![minzipped size](https://badgen.net/bundlephobia/minzip/sdm2)](https://bundlephobia.com/package/sdm2)\n[![Coverage Status](https://coveralls.io/repos/github/JOU-amjs/sdm2/badge.svg)](https://coveralls.io/github/JOU-amjs/sdm2)\n![typescript](https://badgen.net/badge/icon/typescript?icon=typescript\u0026label)\n![license](https://img.shields.io/badge/license-MIT-blue.svg)\n\n## Example\n\n#### Dropdown menu select\n\n![1](https://github.com/JOU-amjs/sdm2/assets/29848971/f7f5fd21-d49b-45b6-94d4-e94c25326f0c)\n\n#### Tree select\n\n![2](https://github.com/JOU-amjs/sdm2/assets/29848971/7f46ad80-f18e-4d61-86f5-85fb908d0dd8)\n\n#### Side menubar\n\n![3](https://github.com/JOU-amjs/sdm2/assets/29848971/85e3a46a-130c-4f9a-89c9-5a62e0b069f8)\n\nComplete example [click here to view](https://codesandbox.io/p/sandbox/github/JOU-amjs/sdm2-example/tree/main?file=%2Fsrc%2FApp.vue)\n\n## 🚀 Features\n\n- easy to use\n- high performance\n- less than 1kb\n- Support TypeScript\n\n## Install\n\n```bash\n# via npm\nnpm install sdm2\n\n#via yarn\nyarn add sdm2\n```\n\nIntroduced in `Node.js`, `esModule`, `Browser`\n\n```javascript\n// commonjs(Node.js)\nvar { match, filterMap } = require('sdm2').default;\n\n// esModule\nimport { match, filterMap } from 'sdm2';\n```\n\nBrowser\n\n```html\n\u003cscript src=\"https://unpkg.com/sdm2\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\nIf you use it in path search, tree control option search, checkbox item search, or other discontiguous string match of local data, it can satisfy you, please see the example below.\n\n### match string\n\n```javascript\nconst ret = match('src/views/home.jsx', 'shojsx');\n/* ret =\u003e {\n   origin: 'src/views/home.jsx',\n   str: 'src/views/home.jsx',\n   strArr: ['src/views/home.jsx'],\n   position: [0, [10, 11], [15, 17]],\n   indexes: [0, 10, 11, 15, 16, 17]\n}\n*/\n\n// return null if not matched\nconst ret = match('src/views/home.jsx', 'ZZZZ');\n// ret =\u003e null\n```\n\n**Return Field Explanation**\n| field name | description |\n| ---- | ---- |\n| origin | The string to be searched, the original value of the first parameter of `match` function |\n| str | The string transformed by `onMatched` after matching keywords, if `onMatched` is not specified, its value is the same as origin |\n| strArr | An array of matched strings and unmatched strings, if `onMatched` is specified, the matched part is the transformed value of `onMatched` |\n| position | The position of matched keyword. If multiple keywords are matched consecutively, it will be represented by `[startIndex, endIndex]` |\n| indexes | The position of the matched keyword in the searched string, different from `position`, even if multiple keywords are matched consecutively, they will be listed one by one |\n\n### Match nested string\n\nIf the string being match is nested within an object, `matchStr` can be used to return the string being matched for.\n\n```javascript\nconst ret = match({ name: 'src/views/home.jsx' }, 'shojsx', {\n\tmatchStr: obj =\u003e obj.name\n});\n/* ret =\u003e {\n   origin: { name: 'src/views/home.jsx' },\n   str: 'src/views/home.jsx',\n   strArr: ['src/views/home.jsx'],\n   position: [0, [10, 11], [15, 17]],\n   indexes: [0, 10, 11, 15, 16, 17]\n}\n*/\n```\n\n### Filter array\n\nFilter an array with unmatched values of `null`.\n\n```javascript\nconst matchedStrings = [\n   'src/views/home.jsx',\n   'src/views/about.jsx',\n   'src/views/ad.jsx',\n];\nconst ret = matchedStrings. filter(strItem =\u003e match(strItem, 'srchom. X', { ignoreCase: true });\n/* ret =\u003e ['src/views/home.jsx'] */\n```\n\n### Highlight matched characters\n\nUse the `onMatched` function to transform the matching string, and the matched keywords can be highlighted.\n\n`onMatched` will be emit every time when a part of keywords are matched, and its parameters are the matched keywords and the original value of this match.\n\n```javascript\nimport { match } from 'sdm2';\nconst ret = match('src/views/home.jsx', 'shojsx', {\n\tonMatched: (matchedStr, origin) =\u003e `\u003cspan class=\"highlight\"\u003e${matchedStr}\u003c/span\u003e`\n});\n/* ret =\u003e {\n   origin: 'src/views/home.jsx',\n   str: '\u003cspan class=\"highlight\"\u003es\u003c/span\u003erc/views/\u003cspan class=\"highlight\"\u003eho\u003c/span\u003eme.\u003cspan class=\"highlight\"\u003ejsx\u003c/span\u003e',\n   strArr: [\n     '\u003cspan class=\"highlight\"\u003es\u003c/span\u003e',\n     'rc/views/',\n     '\u003cspan class=\"highlight\"\u003eho\u003c/span\u003e',\n     'me.',\n     '\u003cspan class=\"highlight\"\u003ejsx\u003c/span\u003e'\n   ],\n   position: [0, [10, 11], [15, 17]],\n   indexes: [0, 10, 11, 15, 16, 17]\n}\n*/\n```\n\n### Filter array and highlight matched characters\n\nIf you want to filter an string array, you can use `filterMap` to filter and transform strings at the same time. `filterMap` will first filter the items that matched keywords, and then call `onMap` by `array.map` to transform the matched items.\n\n```javascript\nimport { filterMap } from 'sdm2';\n\nconst matchedStrings = ['src/views/home.jsx', 'src/views/about.jsx', 'src/views/ad.jsx'];\nconst ret = filterMap(matchedStrings, 'shojsx', {\n\tonMatched: (matchedStr, originStr) =\u003e `\u003cspan class=\"highlight\"\u003e${matchedStr}\u003c/span\u003e`,\n\tonMap: (matchedInfo, index) =\u003e matchedInfo.str\n});\n/* ret =\u003e ['\u003cspan class=\"highlight\"\u003es\u003c/span\u003erc/views/\u003cspan class=\"highlight\"\u003eho\u003c/span\u003eme.\u003cspan class=\"highlight\"\u003ejsx\u003c/ span\u003e']\n */\n```\n\n**jsx syntax highlighting**\n\nMaybe you don't like to use `dangerouslySetInnerHTML`(react) or `v-html`(vue) to highlight keywords, in jsx, you can also return the virtual dom in `onMatched`, and return the splited array in `onMap`, which is more in line with the habits of UI framework.\n\n```jsx\nconst ret = filterMap(matchedStrings, 'shojsx', {\nonMatched: (matchedStr, originStr) =\u003e \u003cspan class=\"highlight\"\u003e${matchedStr}\u003c/span\u003e,\nonMap: (matchedInfo, index) =\u003e matchedInfo.strArr\n});\n\n/* ret =\u003e [\n   VNode {\n     class: 'highlight',\n     children: 's'\n   },\n   'rc/views/',\n   VNode {\n     class: 'highlight',\n     children: 'ho'\n   },\n   'me.',\n   VNode {\n     class: 'highlight',\n     children: 'jsx'\n   }\n]\n```\n\n## Performance\n\n---\n\nYou don't worry about the performance, each searched string will be only compared once, thus ensuring high performance. Below are performance test results for random strings.\n\nThe key string is a 50-digit random string\n| Number of strings | Single string length | Ignoring case | Performance |\n| ---- | ---- | ---- | ---- |\n| 1000 | 5000 | ✅ | 19ms |\n| 1000 | 5000 | ❌ | 16ms |\n| 5000 | 5000 | ✅ | 42ms |\n| 5000 | 5000 | ❌ | 39ms |\n| 10000 | 5000 | ✅ | 101ms |\n| 10000 | 5000 | ❌ | 84ms |\n\n## Welcome to submit issues\n\nIf you encounter difficulties when using sdm2, whether it is a bug or a new function, you can [click here to submit](https://github.com/JOU-amjs/sdm2/issues)\n\n## LICENSE\n\n[MIT](https://en.wikipedia.org/wiki/MIT_License)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjou-amjs%2Fsdm2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjou-amjs%2Fsdm2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjou-amjs%2Fsdm2/lists"}