{"id":13446755,"url":"https://github.com/snd/url-pattern","last_synced_at":"2025-03-21T16:32:47.469Z","repository":{"id":2790027,"uuid":"3790005","full_name":"snd/url-pattern","owner":"snd","description":"easier than regex string matching patterns for urls and other strings. turn strings into data or data into strings.","archived":false,"fork":false,"pushed_at":"2020-08-06T08:43:14.000Z","size":487,"stargazers_count":586,"open_issues_count":13,"forks_count":42,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-13T00:03:43.319Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"CoffeeScript","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/snd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"contributing.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-03-21T18:45:04.000Z","updated_at":"2025-03-12T14:47:21.000Z","dependencies_parsed_at":"2022-09-15T21:02:47.541Z","dependency_job_id":null,"html_url":"https://github.com/snd/url-pattern","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snd%2Furl-pattern","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snd%2Furl-pattern/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snd%2Furl-pattern/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snd%2Furl-pattern/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snd","download_url":"https://codeload.github.com/snd/url-pattern/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244829611,"owners_count":20517342,"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":[],"created_at":"2024-07-31T05:00:58.898Z","updated_at":"2025-03-21T16:32:47.204Z","avatar_url":"https://github.com/snd.png","language":"CoffeeScript","readme":"# url-pattern\n\n[![NPM Package](https://img.shields.io/npm/v/url-pattern.svg?style=flat)](https://www.npmjs.org/package/url-pattern)\n[![Build Status](https://travis-ci.org/snd/url-pattern.svg?branch=master)](https://travis-ci.org/snd/url-pattern/branches)\n[![Sauce Test Status](https://saucelabs.com/buildstatus/urlpattern)](https://saucelabs.com/u/urlpattern)\n[![codecov.io](http://codecov.io/github/snd/url-pattern/coverage.svg?branch=master)](http://codecov.io/github/snd/url-pattern?branch=master)\n[![Downloads per Month](https://img.shields.io/npm/dm/url-pattern.svg?style=flat)](https://www.npmjs.org/package/url-pattern)\n\n**easier than regex string matching patterns for urls and other strings.  \nturn strings into data or data into strings.**\n\n\u003e This is a great little library -- thanks!  \n\u003e [michael](https://github.com/snd/url-pattern/pull/7)\n\n[make pattern:](#make-pattern-from-string)\n``` javascript\nvar pattern = new UrlPattern('/api/users(/:id)');\n```\n\n[match pattern against string and extract values:](#match-pattern-against-string)\n``` javascript\npattern.match('/api/users/10'); // {id: '10'}\npattern.match('/api/users'); // {}\npattern.match('/api/products/5'); // null\n```\n\n[generate string from pattern and values:](#stringify-patterns)\n``` javascript\npattern.stringify() // '/api/users'\npattern.stringify({id: 20}) // '/api/users/20'\n```\n\n- continuously tested in Node.js (0.12, 4.2.3 and 5.3) and all relevant browsers:\n  [![Sauce Test Status](https://saucelabs.com/browser-matrix/urlpattern.svg)](https://saucelabs.com/u/urlpattern)\n- [tiny single file with just under 500 lines of simple, readable, maintainable code](src/url-pattern.coffee)\n- [huge test suite](test)\n  passing [![Build Status](https://travis-ci.org/snd/url-pattern.svg?branch=master)](https://travis-ci.org/snd/url-pattern/branches)\n  with [![codecov.io](http://codecov.io/github/snd/url-pattern/coverage.svg?branch=master)](http://codecov.io/github/snd/url-pattern?branch=master)\n  code coverage\n- widely used [![Downloads per Month](https://img.shields.io/npm/dm/url-pattern.svg?style=flat)](https://www.npmjs.org/package/url-pattern)\n- supports CommonJS, [AMD](http://requirejs.org/docs/whyamd.html) and browser globals\n  - `require('url-pattern')`\n  - use [lib/url-pattern.js](lib/url-pattern.js) in the browser\n  - sets the global variable `UrlPattern` when neither CommonJS nor [AMD](http://requirejs.org/docs/whyamd.html) are available.\n- very fast matching as each pattern is compiled into a regex exactly once\n- zero dependencies\n- [customizable](#customize-the-pattern-syntax)\n- [frequently asked questions](#frequently-asked-questions)\n- npm package: `npm install url-pattern`\n- bower package: `bower install url-pattern`\n- pattern parser implemented using simple, combosable, testable [parser combinators](https://en.wikipedia.org/wiki/Parser_combinator)\n- [typescript typings](index.d.ts)\n\n[check out **passage** if you are looking for simple composable routing that builds on top of url-pattern](https://github.com/snd/passage)\n\n```\nnpm install url-pattern\n```\n\n```\nbower install url-pattern\n```\n\n```javascript\n\u003e var UrlPattern = require('url-pattern');\n```\n\n``` javascript\n\u003e var pattern = new UrlPattern('/v:major(.:minor)/*');\n\n\u003e pattern.match('/v1.2/');\n{major: '1', minor: '2', _: ''}\n\n\u003e pattern.match('/v2/users');\n{major: '2', _: 'users'}\n\n\u003e pattern.match('/v/');\nnull\n```\n``` javascript\n\u003e var pattern = new UrlPattern('(http(s)\\\\://)(:subdomain.):domain.:tld(\\\\::port)(/*)')\n\n\u003e pattern.match('google.de');\n{domain: 'google', tld: 'de'}\n\n\u003e pattern.match('https://www.google.com');\n{subdomain: 'www', domain: 'google', tld: 'com'}\n\n\u003e pattern.match('http://mail.google.com/mail');\n{subdomain: 'mail', domain: 'google', tld: 'com', _: 'mail'}\n\n\u003e pattern.match('http://mail.google.com:80/mail');\n{subdomain: 'mail', domain: 'google', tld: 'com', port: '80', _: 'mail'}\n\n\u003e pattern.match('google');\nnull\n```\n\n## make pattern from string\n\n```javascript\n\u003e var pattern = new UrlPattern('/api/users/:id');\n```\n\na `pattern` is immutable after construction.  \nnone of its methods changes its state.  \nthat makes it easier to reason about.\n\n## match pattern against string\n\nmatch returns the extracted segments:\n\n```javascript\n\u003e pattern.match('/api/users/10');\n{id: '10'}\n```\n\nor `null` if there was no match:\n\n``` javascript\n\u003e pattern.match('/api/products/5');\nnull\n```\n\npatterns are compiled into regexes which makes `.match()` superfast.\n\n## named segments\n\n`:id` (in the example above) is a named segment:\n\na named segment starts with `:` followed by the **name**.  \nthe **name** must be at least one character in the regex character set `a-zA-Z0-9`.\n\nwhen matching, a named segment consumes all characters in the regex character set\n`a-zA-Z0-9-_~ %`.\na named segment match stops at `/`, `.`, ... but not at `_`, `-`, ` `, `%`...\n\n[you can change these character sets. click here to see how.](#customize-the-pattern-syntax)\n\nif a named segment **name** occurs more than once in the pattern string,\nthen the multiple results are stored in an array on the returned object:\n\n```javascript\n\u003e var pattern = new UrlPattern('/api/users/:ids/posts/:ids');\n\u003e pattern.match('/api/users/10/posts/5');\n{ids: ['10', '5']}\n```\n\n## optional segments, wildcards and escaping\n\nto make part of a pattern optional just wrap it in `(` and `)`:\n\n```javascript\n\u003e var pattern = new UrlPattern(\n  '(http(s)\\\\://)(:subdomain.):domain.:tld(/*)'\n);\n```\n\nnote that `\\\\` escapes the `:` in `http(s)\\\\://`.\nyou can use `\\\\` to escape `(`, `)`, `:` and `*` which have special meaning within\nurl-pattern.\n\noptional named segments are stored in the corresponding property only if they are present in the source string:\n\n```javascript\n\u003e pattern.match('google.de');\n{domain: 'google', tld: 'de'}\n```\n\n```javascript\n\u003e pattern.match('https://www.google.com');\n{subdomain: 'www', domain: 'google', tld: 'com'}\n```\n\n`*` in patterns are wildcards and match anything.\nwildcard matches are collected in the `_` property:\n\n```javascript\n\u003e pattern.match('http://mail.google.com/mail');\n{subdomain: 'mail', domain: 'google', tld: 'com', _: 'mail'}\n```\n\nif there is only one wildcard then `_` contains the matching string.\notherwise `_` contains an array of matching strings.\n\n[look at the tests for additional examples of `.match`](test/match-fixtures.coffee)\n\n## make pattern from regex\n\n```javascript\n\u003e var pattern = new UrlPattern(/^\\/api\\/(.*)$/);\n```\n\nif the pattern was created from a regex an array of the captured groups is returned on a match:\n\n```javascript\n\u003e pattern.match('/api/users');\n['users']\n\n\u003e pattern.match('/apiii/test');\nnull\n```\n\nwhen making a pattern from a regex\nyou can pass an array of keys as the second argument.\nreturns objects on match with each key mapped to a captured value:\n\n```javascript\n\u003e var pattern = new UrlPattern(\n  /^\\/api\\/([^\\/]+)(?:\\/(\\d+))?$/,\n  ['resource', 'id']\n);\n\n\u003e pattern.match('/api/users');\n{resource: 'users'}\n\n\u003e pattern.match('/api/users/5');\n{resource: 'users', id: '5'}\n\n\u003e pattern.match('/api/users/foo');\nnull\n```\n\n## stringify patterns\n\n```javascript\n\u003e var pattern = new UrlPattern('/api/users/:id');\n\n\u003e pattern.stringify({id: 10})\n'/api/users/10'\n```\n\noptional segments are only included in the output if they contain named segments\nand/or wildcards and values for those are provided:\n\n```javascript\n\u003e var pattern = new UrlPattern('/api/users(/:id)');\n\n\u003e pattern.stringify()\n'/api/users'\n\n\u003e pattern.stringify({id: 10})\n'/api/users/10'\n```\n\nwildcards (key = `_`), deeply nested optional groups and multiple value arrays should stringify as expected.\n\nan error is thrown if a value that is not in an optional group is not provided.\n\nan error is thrown if an optional segment contains multiple\nparams and not all of them are provided.\n*one provided value for an optional segment\nmakes all values in that optional segment required.*\n\n[look at the tests for additional examples of `.stringify`](test/stringify-fixtures.coffee)\n\n## customize the pattern syntax\n\nfinally we can completely change pattern-parsing and regex-compilation to suit our needs:\n\n```javascript\n\u003e var options = {};\n```\n\nlet's change the char used for escaping (default `\\\\`):\n\n```javascript\n\u003e options.escapeChar = '!';\n```\n\nlet's change the char used to start a named segment (default `:`):\n\n```javascript\n\u003e options.segmentNameStartChar = '$';\n```\n\nlet's change the set of chars allowed in named segment names (default `a-zA-Z0-9`)\nto also include `_` and `-`:\n\n```javascript\n\u003e options.segmentNameCharset = 'a-zA-Z0-9_-';\n```\n\nlet's change the set of chars allowed in named segment values\n(default `a-zA-Z0-9-_~ %`) to not allow non-alphanumeric chars:\n\n```javascript\n\u003e options.segmentValueCharset = 'a-zA-Z0-9';\n```\n\nlet's change the chars used to surround an optional segment (default `(` and `)`):\n\n```javascript\n\u003e options.optionalSegmentStartChar = '[';\n\u003e options.optionalSegmentEndChar = ']';\n```\n\nlet's change the char used to denote a wildcard (default `*`):\n\n```javascript\n\u003e options.wildcardChar = '?';\n```\n\npass options as the second argument to the constructor:\n\n```javascript\n\u003e var pattern = new UrlPattern(\n  '[http[s]!://][$sub_domain.]$domain.$toplevel-domain[/?]',\n  options\n);\n```\n\nthen match:\n\n```javascript\n\u003e pattern.match('http://mail.google.com/mail');\n{\n  sub_domain: 'mail',\n  domain: 'google',\n  'toplevel-domain': 'com',\n  _: 'mail'\n}\n```\n\n## frequently asked questions\n\n### how do i match the query part of an URL ?\n\nthe query part of an URL has very different semantics than the rest.\nurl-pattern is not well suited for parsing the query part.\n\nthere are good existing libraries for parsing the query part of an URL.\nhttps://github.com/hapijs/qs is an example.\nin the interest of keeping things simple and focused\ni see no reason to add special support\nfor parsing the query part to url-pattern.\n\ni recommend splitting the URL at `?`, using url-pattern\nto parse the first part (scheme, host, port, path)\nand using https://github.com/hapijs/qs to parse the last part (query).\n\n### how do i match an IP ?\n\nyou can't exactly match IPs with url-pattern so you have to\nfall back to regexes and pass in a regex object.\n\n[here's how you do it](https://github.com/snd/url-pattern/blob/c8e0a943bb62e6feeca2d2595da4e22782e617ed/test/match-fixtures.coffee#L237)\n\n## [contributing](contributing.md)\n\n## [license: MIT](LICENSE)\n","funding_links":[],"categories":["Packages","CoffeeScript","Repository","包","String","目录","String [🔝](#readme)","URL","字符串","Number"],"sub_categories":["URL","Runner","运行器","运行器e2e测试"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnd%2Furl-pattern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnd%2Furl-pattern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnd%2Furl-pattern/lists"}