{"id":23108596,"url":"https://github.com/gebv/strparam","last_synced_at":"2025-04-03T23:14:23.730Z","repository":{"id":48895034,"uuid":"260132608","full_name":"gebv/strparam","owner":"gebv","description":"parameterized pattern matching (faster alternative to golang regexp)","archived":false,"fork":false,"pushed_at":"2021-07-06T17:22:43.000Z","size":100,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-09T10:47:55.627Z","etag":null,"topics":["golang","golang-library","regular-expression","string-matching"],"latest_commit_sha":null,"homepage":"","language":"Go","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/gebv.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}},"created_at":"2020-04-30T06:35:58.000Z","updated_at":"2021-07-06T17:19:12.000Z","dependencies_parsed_at":"2022-09-12T15:24:51.164Z","dependency_job_id":null,"html_url":"https://github.com/gebv/strparam","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gebv%2Fstrparam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gebv%2Fstrparam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gebv%2Fstrparam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gebv%2Fstrparam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gebv","download_url":"https://codeload.github.com/gebv/strparam/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247092393,"owners_count":20882218,"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":["golang","golang-library","regular-expression","string-matching"],"created_at":"2024-12-17T01:28:19.036Z","updated_at":"2025-04-03T23:14:23.711Z","avatar_url":"https://github.com/gebv.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# strparam\n\n![CI Status](https://github.com/gebv/strparam/workflows/Go/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/gebv/strparam)](https://goreportcard.com/report/github.com/gebv/strparam)\n[![codecov](https://codecov.io/gh/gebv/strparam/branch/master/graph/badge.svg)](https://codecov.io/gh/gebv/strparam)\n\n40 times faster аlternative to regex for string matching by pattern and extract params. This is solution as a middle point between simple strings and regular expressions.\n\nFeatures\n* correctly parses UTF-8 characters\n* faster than regular expression\n* [multiple pattern match](#multiple-pattern-match)\n\n## Introduction\n\nFor example. Need to parse the following pattern `foo=(..), baz=(..), golang`. Instead of `..` can be any value.\nWith regexp, the solution would look something like this.\n\n```golang\nin := \"foo=(bar), baz=(日本語), golang\"\nre := regexp.MustCompile(`foo=\\((.*)\\), baz=\\((.*)\\), golang`)\nre.FindAllStringSubmatch(str, -1)\n// [[foo=(bar), baz=(日本語), golang bar 日本語]]\n```\n[On the playground](https://play.golang.org/p/_ENJU_Mjnty)\n\nOr even like this.\n\n```golang\nin := \"foo=(bar), baz=(日本語), golang\"\nre := regexp.MustCompile(`\\(([^)]+)\\)`)\nrex.FindAllStringSubmatch(str, -1)\n// [[(bar) bar] [(日本語) 日本語]]\n```\n[On the playground](https://play.golang.org/p/SSpy7iiINow)\n\nBut regular expressions is slow on golang.\n\nFollow the benchmarks for naive solution on regexp (see above) and method `Loockup` for parsed patterns.\n\n```\nBenchmarkParamsViaRegexp1\nBenchmarkParamsViaRegexp1-4                \t   23230\t     56140 ns/op\t   19258 B/op\t       5 allocs/op\nBenchmarkParamsViaRegexp2\nBenchmarkParamsViaRegexp2-4                \t   52396\t     23079 ns/op\t   28310 B/op\t       8 allocs/op\nBenchmarkParamsViaStrparam_NumParams2\nBenchmarkParamsViaStrparam_NumParams2-4    \t  315464\t      3467 ns/op\t     295 B/op\t       1 allocs/op\nBenchmarkParamsViaStrparam_NumParams5\nBenchmarkParamsViaStrparam_NumParams5-4    \t  193682\t      5444 ns/op\t     296 B/op\t       1 allocs/op\nBenchmarkParamsViaStrparam_NumParams20\nBenchmarkParamsViaStrparam_NumParams20-4   \t   72276\t     18467 ns/op\t     297 B/op\t       1 allocs/op\n```\n\nFaster solution.\n\n```golang\nin := \"foo=(bar), baz=(日本語), golang\"\ns, _ := Parse(\"foo=({p1}), baz=({p2}), golang\")\nfound, params := s.Lookup(in)\n// true [{Name:p1 Value:bar} {Name:p2 Value:日本語}]\n```\n\n[On the playground](https://play.golang.org/p/qsj5fNJfPvO)\n\n## Multiple pattern match\n\nPerforming multiple pattern match for input string. To use a variety of patterns.\n\nAt same level the patterns are sorted (by number of childs and by length constatnt token value) from top to down\n\nSorting rules:\n- CONST type token has the highest weight\n- longer CONST type token has a higher weight\n- token with more childs has a higher weight\n\nTODO: more details on engine a multiple pattern matching\n\n```golang\nr := NewStore()\nr.Add(\"foo2{p1}foo2{p2}golang\")\nr.Add(\"foo1{p3}foo1{p4}golang\")\n\nin := \"foo1XXXfoo1YYYgolang\"\n\nschema := r.Find(in)\nfound, params := schema.Lookup(in)\n```\n\nFollow the benchmarks for method `Store.Find` (without extracting parameters).\n\n```\nBenchmarkStore_Lookup_2_2\nBenchmarkStore_Lookup_2_2-4                \t  255735\t      4071 ns/op\t     160 B/op\t       2 allocs/op\nBenchmarkStore_Lookup_2_102\nBenchmarkStore_Lookup_2_102-4              \t  108709\t     12170 ns/op\t     160 B/op\t       2 allocs/op\n```\n\n[On the playground](https://play.golang.org/p/qmHhv_b_1pj)\n\n## Guide\n\n### Installation\n\n```\ngo get github.com/gebv/strparam\n```\n\n### Example\n\nExample for a quick start.\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gebv/strparam\"\n)\n\nfunc main() {\n\tin := \"foo=(bar), baz=(日本語), golang\"\n\ts, _ := strparam.Parse(\"foo=({p1}), baz=({p2}), golang\")\n\tok, params := s.Lookup(in)\n    fmt.Printf(\"%v %+v\", ok, params)\n}\n\n```\n\n[On the playground](https://play.golang.org/p/dll0rZYYAlP)\n\n## How does it work?\n\nPattern is parse into array of\n* tokens with offset information in bytes **for constants**.\n* tokens with information of parameter (parameter name and other information).\n\nThis pattern `foo=({p1}), baz=({p2}), golang` looks like an array\n```\n[\n    {Mode:begin}\n    {Mode:pattern Len:5 Raw:\"foo=(\"} // constant\n    {Mode:parameter Raw:\"{p1}\"}\n    {Mode:pattern Len:8 Raw:\"), baz=(\"}\n    {Mode:parameter Raw:\"{p2}\"}\n    {Mode:pattern Len:9 Raw:\"), golang\"}\n    {Mode:end}\n]\n```\n\nAt the time of parsing the incoming string move around the token array if each token matches. Moving from token to token, we keep the general offset (matching shift). For parameters, look for the next constant (search window) or end of line.\n\nPrefix-tree is used to store the list of patterns.\n\nFor example the follow next patterns:\n\n* `foo{p1}bar`\n* `foo{p1}baz`\n\n```\nroot\n    └── foo\n        └── {p1}\n\t        ├── bar\n\t        └── baz\n```\n\nAs parsing incoming string we are moving to deep in the tree.\n\n## TODO\n\n- [x] multiple patterns, lookup and extract params\n- [ ] extend parameters for internal validators, eg `{paramName required, len=10}`\n- [ ] external validators via hooks\n- [ ] stream parser\n- [ ] sets weight for equal childs (for sorting), eg `{paramName1 weight=100}`, `{paramName2 weight=200}` (specific case?)\n\n# License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgebv%2Fstrparam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgebv%2Fstrparam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgebv%2Fstrparam/lists"}