{"id":17271814,"url":"https://github.com/jawj/js-xre","last_synced_at":"2025-04-14T08:20:30.364Z","repository":{"id":57283906,"uuid":"58918504","full_name":"jawj/js-xre","owner":"jawj","description":"A small, focused, forward-looking library for extended Regular Expressions in JavaScript, using ES2015+ tagged template literals","archived":false,"fork":false,"pushed_at":"2020-09-16T06:23:10.000Z","size":19,"stargazers_count":24,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T21:52:04.026Z","etag":null,"topics":["expression","extended","javascript","regex","regexp","regular","tagged-template-literals","typescript"],"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/jawj.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":"2016-05-16T09:03:23.000Z","updated_at":"2024-10-23T10:57:18.000Z","dependencies_parsed_at":"2022-09-19T20:43:37.767Z","dependency_job_id":null,"html_url":"https://github.com/jawj/js-xre","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fjs-xre","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fjs-xre/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fjs-xre/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jawj%2Fjs-xre/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jawj","download_url":"https://codeload.github.com/jawj/js-xre/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248844036,"owners_count":21170505,"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":["expression","extended","javascript","regex","regexp","regular","tagged-template-literals","typescript"],"created_at":"2024-10-15T08:47:05.859Z","updated_at":"2025-04-14T08:20:30.338Z","avatar_url":"https://github.com/jawj.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xRE: extended RegExps for JavaScript ES2015+\n\nExtended Regular Expressions in JavaScript using, ES2015+ tagged template literals.\n\nSmall: \u003c 1 KB gzipped. Focused: it doesn't do a lot else (disclosure: it does do properly multiline expressions too). And forward-looking (which is a nice way of saying you'll need a recent node version or modern browser to enjoy it). \n\n## Installation and use\n\n### Browser\n\n```html\n\u003cscript src=\"js-xre.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  const myRegExp = xRE `^\\d$ # just one digit` `x`;\n\u003c/script\u003e\n```\n\n### Node\n\n`npm install js-xre`\n\nthen\n\n```javascript\n  const xRE = require('js-xre');\n  const myRegExp = xRE `^\\d$ # just one digit` `x`;\n```\n\n## What's an extended RegExp?\n\nPerl, Ruby, and some other languages support a readable _extended_ regular expression syntax, in which literal whitespace is ignored and comments (starting with `#`) are available. This is triggered with the `x` flag.\n\n(Don't confuse this with the 'extended' expressions of `egrep`, which are just modern regular expressions. The sort of extended expressions I am talking about might perhaps be better be described as _commented_ or even _literate_).\n\nFor example, as far as Ruby is concerned,\n\n```regexp\n/\\d(?=(\\d{3})+\\b)/\n```\n\nand\n\n```regexp\n/(?x)\n  \\d          # a digit\n  (?=         # followed by (look-ahead match)\n    (\\d{3})+  # one or more sets of three digits\n    \\b        # and then a word boundary\n  )\n/\n```\n\nare equivalent. For humans, however, the extended second version is obviously much easier to get to grips with.\n\nThese languages also support a properly multi-line match mode, where the `.` character really does match anything, including `\\n`.\n\n## JS: no dice —\n\nJavaScript traditionally offers neither of these options. \n\nIt doesn’t recognise the extended syntax, and its multi-line support consists only in permitting the `^` and `$` characters to match the beginnings and ends of lines within a string. It will never allow the `.` to match `\\n`.\n\nI first wrote a function to convert extended and fully-multi-line RegExp source strings to standard syntax [in 2010](http://blog.mackerron.com/2010/08/08/extended-multi-line-js-regexps/). But it was tricky and error-prone to use it, because a standard JS string can't span multiple lines and you would have to backslash-escape all the backslashes.\n\n## — until now\n\nES2015's pleasingly flexible [tagged template literals](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals) now make this a genuinely usable and useful capability. \n\nAs implemented here, the syntax is:\n\n```javascript\nxRE `myregexp` `flags`\n```\n\n(Note: the `flags` argument is required — to specify no flags, use an empty literal, ``` `` ```).\n\nIn addition to the standard flags (`i`, `g`, `m`, `y`, `u`), which are passed straight through to the native `RegExp`, three additional flags are provided:\n\n* `x` activates extended mode, stripping out whitespace and comments\n* `mm` activates genuinely-multi-line mode, where `.` matches anything, including newlines (achieved by replacing `.` with `[\\s\\S]`)\n* `b` is for backslashes, and automatically escapes all template expressions so they are treated as literal text (alternatively, an `xRE.escape` method is provided so this can be done case-by-case).\n\n## Alternatives\n\nYou should also check out [XRegExp](http://xregexp.com/), an impressive library that takes a rather more and-the-kitchen-sink approach. The complete version of XRegExp is 62 KB gzipped, against this library's few hundred bytes.\n\n\n## Examples\n\n### `x` for extended\n\nAn simple example with the extended flag `x`:\n\n```js\nconst xRE = require('js-xre');\n\nconst digitsThatNeedSeparators = xRE `\n  \\d          # a digit\n  (?=         # followed by (look-ahead match)\n    (\\d{3})+  # one or more sets of three digits\n    \\b        # and then a word boundary\n  )\n` `xg`;\n\nconsole.log(digitsThatNeedSeparators);  \n// /\\d(?=(\\d{3})+\\b)/g\n\nconst separate000s = (n, sep = '\\u202f') =\u003e\n  String(n).replace(digitsThatNeedSeparators, '$\u0026' + sep);\n\nconsole.log(separate000s(1234567));\n// 1 234 567\n```\n\nAnd a monstrously complex example: [Daring Fireball's URL RegExp](http://daringfireball.net/2010/07/improved_regex_for_matching_urls):\n\n```js \nconst xRE = require('js-xre');\n\nconst url = xRE `\n  \\b\n  (?:\n    [a-z][\\w-]+:                        # URL protocol and colon\n    (?:\n      /{1,3}                              # 1-3 slashes\n      |                                   # or\n      [a-z0-9%]                           # single letter or digit or '%'\n                                          # (trying not to match e.g. \"URI::Escape\")\n    )\n    |                                   # or\n    www\\d{0,3}[.]                       # \"www.\", \"www1.\", \"www2.\" … \"www999.\"\n    |                                   # or\n    [a-z0-9.\\-]+[.][a-z]{2,4}/          # looks like domain name followed by a slash\n  )\n  (?:                                   # one or more:\n    [^\\s()\u003c\u003e]+                            # run of non-space, non-()\u003c\u003e\n    |                                     # or\n    \\(([^\\s()\u003c\u003e]+|(\\([^\\s()\u003c\u003e]+\\)))*\\)    # balanced parens, up to 2 levels\n  )+\n  (?:                                   # end with:\n    \\(([^\\s()\u003c\u003e]+|(\\([^\\s()\u003c\u003e]+\\)))*\\)    # balanced parens, up to 2 levels\n    |                                     # or\n    [^\\s\\`!()\\[\\]{};:'\".,\u003c\u003e?«»“”‘’]       # not a space or one of these punct chars\n  )\n` `xig`;\n\nconsole.log(url); \n// /\\b(?:[a-z][\\w-]+:(?:\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\/)(?:[^\\s()\u003c\u003e]+|\\(([^\\s()\u003c\u003e]+|(\\([^\\s()\u003c\u003e]+\\)))*\\))+(?:\\(([^\\s()\u003c\u003e]+|(\\([^\\s()\u003c\u003e]+\\)))*\\)|[^\\s\\`!()\\[\\]{};:'\".,\u003c\u003e?«»“”‘’])/gi\n\nconsole.log('Please visit http://mackerron.com.'.replace(url, '\u003ca href=\"$\u0026\"\u003e$\u0026\u003c/a\u003e'));  \n// Please visit \u003ca href=\"http://mackerron.com\"\u003ehttp://mackerron.com\u003c/a\u003e.\n```\n    \n### `mm` for massively multiline\n\nSerious HTML wrangling should be done with XPath or similar, of course. But:\n\n```js\nconst xRE = require('js-xre');\n\nconst html = `\n  \u003cp\u003eA paragraph on one line.\u003c/p\u003e\n  \u003cp\u003eA paragraph which, by contrast,\n  spans multiple lines.\u003c/p\u003e\n`;\n\nconst mPara  = xRE `\u003cp\\b.+?\u003c/p\u003e` `mg`;\nconsole.log(mPara);\n// /\u003cp\\b.+?\u003c\\/p\u003e/gm\n\nconsole.log(html.match(mPara));\n// [ '\u003cp\u003eA paragraph on one line.\u003c/p\u003e' ]\n\nconst mmPara = xRE `\u003cp\\b.+?\u003c/p\u003e` `mmg`;  // note: mm\nconsole.log(mmPara);\n// /\u003cp\\b[\\s\\S]+?\u003c\\/p\u003e/gm\n\nconsole.log(html.match(mmPara));\n// [ '\u003cp\u003eA paragraph on one line.\u003c/p\u003e',\n//   '\u003cp\u003eA paragraph which, by contrast,\\n  spans multiple lines.\u003c/p\u003e' ]\n```\n\n### `b` for backslashes\n\nSince our syntax for extended regular expressions uses template strings, you can interpolate any `${value}` in there. The `b` flag causes all values to be automatically escaped, so that they're treated as literal text rather then metacharacters.\n\nFor example, say you're allowing users to type in something to find all matches:\n\n```js\nconst xRE = require('js-xre');\n\nconst searchText = '12.6';  // this might come from an \u003cinput\u003e field\nconst search = xRE `^${searchText}$` `bg`;\n\nconsole.log(search);\n// /^12\\.6$/g\n```\n\nThe alternative (useful if you want to mix-and-match your escaping for any reason) is to use the `escape` method of the main function:\n\n```js\nconst xRE = require('js-xre');\n\nconst searchText = '12.6';  // might come from an \u003cinput type=\"text\" /\u003e\nconst anchorStart = true;   // might come from an \u003cinput type=\"checkbox\" /\u003e\nconst anchorEnd = false;    // might come from an \u003cinput type=\"checkbox\" /\u003e\n\nconst search = xRE `\n  ${anchorStart ? '^' : ''}\n  ${xRE.escape(searchText)}\n  ${anchorEnd ? '$' : ''}\n` `gx`;\n\nconsole.log(search);\n// /^12\\.6/g\n```\n\n## Usage as a regular function\n\n`xRE` can also be called as a regular (non-tagged-template) function. This could be useful if you wanted to create an extended regular expression based on user input in a `\u003ctextarea\u003e`, say.\n\nFor instance:\n\n```javascript\n// earlier: \u003cscript src=\"js-xre.js\"\u003e\u003c/script\u003e\n\nconst make = (tag) =\u003e document.body.appendChild(document.createElement(tag));\nconst source = make('textarea');\nconst flags = make('input');\nconst output = make('div');\n\nsource.oninput = flags.oninput = () =\u003e\n  output.innerHTML = xRE(source.value)(flags.value);\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawj%2Fjs-xre","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjawj%2Fjs-xre","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjawj%2Fjs-xre/lists"}