https://github.com/francisrstokes/super-expressive Skip to content Sign up * Why GitHub? Features - + Mobile - + Actions - + Codespaces - + Packages - + Security - + Code review - + Project management - + Integrations - + GitHub Sponsors - + Customer stories - + Security - * Team * Enterprise * Explore + Explore GitHub - Learn & contribute + Topics - + Collections - + Trending - + Learning Lab - + Open source guides - Connect with others + The ReadME Project - + Events - + Community forum - + GitHub Education - + GitHub Stars program - * Marketplace * Pricing Plans - + Compare plans - + Contact Sales - + Nonprofit - + Education - [ ] [search-key] * # In this repository All GitHub | Jump to | * No suggested jump to results * # In this repository All GitHub | Jump to | * # In this user All GitHub | Jump to | * # In this repository All GitHub | Jump to | Sign in Sign up {{ message }} francisrstokes / super-expressive * Watch 34 * Star 3.9k * Fork 119 Super Expressive is a zero-dependency JavaScript library for building regular expressions in (almost) natural language MIT License 3.9k stars 119 forks Star Watch * Code * Issues 7 * Pull requests 0 * Actions * Projects 0 * Security * Insights More * Code * Issues * Pull requests * Actions * Projects * Security * Insights master 1 branch 0 tags Go to file Code Clone HTTPS GitHub CLI [https://github.com/f] Use Git or checkout with SVN using the web URL. [gh repo clone franci] Work fast with our official CLI. Learn more. * Open with GitHub Desktop * Download ZIP Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Go back Launching GitHub Desktop If nothing happens, download GitHub Desktop and try again. Go back Launching Xcode If nothing happens, download Xcode and try again. Go back Launching Visual Studio If nothing happens, download the GitHub extension for Visual Studio and try again. Go back Latest commit @francisrstokes francisrstokes Add hiy's ruby port to the readme (#35) ... 7bc42bb Oct 28, 2020 Add hiy's ruby port to the readme (#35) 7bc42bb Git stats * 55 commits Files Permalink Failed to load latest commit information. Type Name Latest commit message Commit time .github Include a github workflow for tests and coverage reporting Jul 17, 2020 .gitignore Add nyc for test coverage Jul 15, 2020 .npmignore Add a reference to super expressive playground Aug 1, 2020 LICENSE Add license Jul 15, 2020 index.d.ts Add lookBehind (assertBehind / assertNotBehind) support (#33) Oct 25, 2020 index.js Add lookBehind (assertBehind / assertNotBehind) support (#33) Oct 25, 2020 index.test.js Add lookBehind (assertBehind / assertNotBehind) support (#33) Oct 25, 2020 logo.png Initial commit Jul 14, 2020 package-lock.json Add lookBehind (assertBehind / assertNotBehind) support (#33) Oct 25, 2020 package.json Add lookBehind (assertBehind / assertNotBehind) support (#33) Oct 25, 2020 playground-small.jpg Add a reference to super expressive playground Aug 1, 2020 readme.md Add hiy's ruby port to the readme (#35) Oct 28, 2020 View code readme.md Super Expressive Super Expressive Logo Super Expressive is a JavaScript library that allows you to build regular expressions in almost natural language - with no extra dependencies, and a lightweight code footprint (less than 4kb with minification + gzip!). --------------------------------------------------------------------- * Why * Installation and Usage * Example * Playground * Ports * API Click to expand + SuperExpressive() + .allowMultipleMatches + .lineByLine + .caseInsensitive + .sticky + .unicode + .singleLine + .anyChar + .whitespaceChar + .nonWhitespaceChar + .digit + .nonDigit + .word + .nonWord + .wordBoundary + .nonWordBoundary + .newline + .carriageReturn + .tab + .nullByte + .anyOf + .capture + .namedCapture(name) + .backreference(index) + .namedBackreference(index) + .group + .end() + .assertAhead + .assertNotAhead + .assertBehind + .assertNotBehind + .optional + .zeroOrMore + .zeroOrMoreLazy + .oneOrMore + .oneOrMoreLazy + .exactly(n) + .atLeast(n) + .between(x, y) + .betweenLazy(x, y) + .startOfInput + .endOfInput + .anyOfChars(chars) + .anythingButChars(chars) + .anythingButString(str) + .anythingButRange(a, b) + .string(s) + .char(c) + .range(a, b) + .subexpression(expr, opts) + .toRegexString() + .toRegex() Why? Regex is a very powerful tool, but its terse and cryptic vocabulary can make constructing and communicating them with others a challenge. Even developers who understand them well can have trouble reading their own back just a few months later! In addition, they can't be easily created and manipulated in a programmatic way - closing off an entire avenue of dynamic text processing. That's where Super Expressive comes in. It provides a programmatic and human readable way to create regular expressions. It's API uses the fluent builder pattern, and is completely immutable. It's built to be discoverable and predictable: * properties and methods describe what they do in plain English * order matters! quantifiers are specified before the thing they change, just like in English (e.g. SuperExpressive().exactly (5).digit) * if you make a mistake, you'll know how to fix it. SuperExpressive will guide you towards a fix if your expression is invalid * subexpressions can be used to create meaningful, reusable components * includes an index.d.ts file for full TypeScript support SuperExpressive turns those complex and unwieldy regexes that appear in code reviews into something that can be read, understood, and properly reviewed by your peers - and maintained by anyone! Installation and Usage npm i super-expressive const SuperExpressive = require('super-expressive'); // Or as an ES6 module import SuperExpressive from 'super-expressive'; Example The following example recognises and captures the value of a 16-bit hexadecimal number like 0xC0D3. const SuperExpressive = require('super-expressive'); const myRegex = SuperExpressive() .startOfInput .optional.string('0x') .capture .exactly(4).anyOf .range('A', 'F') .range('a', 'f') .range('0', '9') .end() .end() .endOfInput .toRegex(); // Produces the following regular expression: /^(?:0x)?([A-Fa-f0-9]{4})$/ Playground You can experiment with SuperExpressive in the Super Expressive Playground by @nartc. This is a great way to build a regex description, and test it against various inputs. [playground] Ports Super Expressive has been ported to the following langauges: PHP https://github.com/bassim/super-expressive-php by @bassim Ruby https://github.com/hiy/super-expressive-ruby by @hiy API SuperExpressive() SuperExpressive() Creates an instance of SuperExpressive. .allowMultipleMatches Uses the g flag on the regular expression, which indicates that it should match multiple values when run on a string. Example SuperExpressive() .allowMultipleMatches .string('hello') .toRegex(); // -> /hello/g .lineByLine Uses the m flag on the regular expression, which indicates that it should treat the .startOfInput and .endOfInput markers as the start and end of lines. Example SuperExpressive() .lineByLine .string('^hello$') .toRegex(); // -> /\^hello\$/m .caseInsensitive Uses the i flag on the regular expression, which indicates that it should treat ignore the uppercase/lowercase distinction when matching. Example SuperExpressive() .caseInsensitive .string('HELLO') .toRegex(); // -> /HELLO/i .sticky Uses the y flag on the regular expression, which indicates that it should create a stateful regular expression that can be resumed from the last match. Example SuperExpressive() .sticky .string('hello') .toRegex(); // -> /hello/y .unicode Uses the u flag on the regular expression, which indicates that it should use full unicode matching. Example SuperExpressive() .unicode .string('hello') .toRegex(); // -> /hello/u .singleLine Uses the s flag on the regular expression, which indicates that the input should be treated as a single line, where the .startOfInput and .endOfInput markers explicitly mark the start and end of input, and .anyChar also matches newlines. Example SuperExpressive() .singleLine .string('hello') .anyChar .string('world') .toRegex(); // -> /hello.world/s .anyChar Matches any single character. When combined with .singleLine, it also matches newlines. Example SuperExpressive() .anyChar .toRegex(); // -> /./ .whitespaceChar Matches any whitespace character, including the special whitespace characters: \r\n\t\f\v. Example SuperExpressive() .whitespaceChar .toRegex(); // -> /\s/ .nonWhitespaceChar Matches any non-whitespace character, excluding also the special whitespace characters: \r\n\t\f\v. Example SuperExpressive() .nonWhitespaceChar .toRegex(); // -> /\S/ .digit Matches any digit from 0-9. Example SuperExpressive() .digit .toRegex(); // -> /\d/ .nonDigit Matches any non-digit. Example SuperExpressive() .nonDigit .toRegex(); // -> /\D/ .word Matches any alpha-numeric (a-z, A-Z, 0-9) characters, as well as _. Example SuperExpressive() .word .toRegex(); // -> /\w/ .nonWord Matches any non alpha-numeric (a-z, A-Z, 0-9) characters, excluding _ as well. Example SuperExpressive() .nonWord .toRegex(); // -> /\W/ .wordBoundary Matches (without consuming any characters) immediately between a character matched by .word and a character not matched by .word (in either order). Example SuperExpressive() .digit .wordBoundary .toRegex(); // -> /\d\b/ .nonWordBoundary Matches (without consuming any characters) at the position between two characters matched by .word. Example SuperExpressive() .digit .nonWordBoundary .toRegex(); // -> /\d\B/ .newline Matches a \n character. Example SuperExpressive() .newline .toRegex(); // -> /\n/ .carriageReturn Matches a \r character. Example SuperExpressive() .carriageReturn .toRegex(); // -> /\r/ .tab Matches a \t character. Example SuperExpressive() .tab .toRegex(); // -> /\t/ .nullByte Matches a \u0000 character (ASCII 0). Example SuperExpressive() .nullByte .toRegex(); // -> /\0/ .anyOf Matches a choice between specified elements. Needs to be finalised with .end(). Example SuperExpressive() .anyOf .range('a', 'f') .range('0', '9') .string('XXX') .end() .toRegex(); // -> /(?:XXX|[a-f0-9])/ .capture Creates a capture group for the proceeding elements. Needs to be finalised with .end(). Can be later referenced with backreference (index). Example SuperExpressive() .capture .range('a', 'f') .range('0', '9') .string('XXX') .end() .toRegex(); // -> /([a-f][0-9]XXX)/ .namedCapture(name) Creates a named capture group for the proceeding elements. Needs to be finalised with .end(). Can be later referenced with namedBackreference(name) or backreference(index). Example SuperExpressive() .namedCapture('interestingStuff') .range('a', 'f') .range('0', '9') .string('XXX') .end() .toRegex(); // -> /(?[a-f][0-9]XXX)/ .namedBackreference(name) Matches exactly what was previously matched by a namedCapture. Example SuperExpressive() .namedCapture('interestingStuff') .range('a', 'f') .range('0', '9') .string('XXX') .end() .string('something else') .namedBackreference('interestingStuff') .toRegex(); // -> /(?[a-f][0-9]XXX)something else\k/ .backreference(index) Matches exactly what was previously matched by a capture or namedCapture using a positional index. Note regex indexes start at 1, so the first capture group has index 1. Example SuperExpressive() .capture .range('a', 'f') .range('0', '9') .string('XXX') .end() .string('something else') .backreference(1) .toRegex(); // -> /([a-f][0-9]XXX)something else\1/ .group Creates a non-capturing group of the proceeding elements. Needs to be finalised with .end(). Example SuperExpressive() .optional.group .range('a', 'f') .range('0', '9') .string('XXX') .end() .toRegex(); // -> /(?:[a-f][0-9]XXX)?/ .end() Signifies the end of a SuperExpressive grouping, such as .anyOf, .group, or .capture. Example SuperExpressive() .capture .anyOf .range('a', 'f') .range('0', '9') .string('XXX') .end() .end() .toRegex(); // -> /((?:XXX|[a-f0-9]))/ .assertAhead Assert that the proceeding elements are found without consuming them. Needs to be finalised with .end(). Example SuperExpressive() .assertAhead .range('a', 'f') .end() .range('a', 'z') .toRegex(); // -> /(?=[a-f])[a-z]/ .assertNotAhead Assert that the proceeding elements are not found without consuming them. Needs to be finalised with .end(). Example SuperExpressive() .assertNotAhead .range('a', 'f') .end() .range('g', 'z') .toRegex(); // -> /(?![a-f])[g-z]/ .assertBehind Assert that the elements contained within are found immediately before this point in the string. Needs to be finalised with .end(). Example SuperExpressive() .assertBehind .string('hello ') .end() .string('world') .toRegex(); // -> /(?<=hello )world/ .assertNotBehind Assert that the elements contained within are not found immediately before this point in the string. Needs to be finalised with .end(). Example SuperExpressive() .assertNotBehind .string('hello ') .end() .string('world') .toRegex(); // -> /(? /\d?/ .zeroOrMore Assert that the proceeding element may not be matched, or may be matched multiple times. Example SuperExpressive() .zeroOrMore.digit .toRegex(); // -> /\d*/ .zeroOrMoreLazy Assert that the proceeding element may not be matched, or may be matched multiple times, but as few times as possible. Example SuperExpressive() .zeroOrMoreLazy.digit .toRegex(); // -> /\d*?/ .oneOrMore Assert that the proceeding element may be matched once, or may be matched multiple times. Example SuperExpressive() .oneOrMore.digit .toRegex(); // -> /\d+/ .oneOrMoreLazy Assert that the proceeding element may be matched once, or may be matched multiple times, but as few times as possible. Example SuperExpressive() .oneOrMoreLazy.digit .toRegex(); // -> /\d+?/ .exactly(n) Assert that the proceeding element will be matched exactly n times. Example SuperExpressive() .exactly(5).digit .toRegex(); // -> /\d{5}/ .atLeast(n) Assert that the proceeding element will be matched at least n times. Example SuperExpressive() .atLeast(5).digit .toRegex(); // -> /\d{5,}/ .between(x, y) Assert that the proceeding element will be matched somewhere between x and y times. Example SuperExpressive() .between(3, 5).digit .toRegex(); // -> /\d{3,5}/ .betweenLazy(x, y) Assert that the proceeding element will be matched somewhere between x and y times, but as few times as possible. Example SuperExpressive() .betweenLazy(3, 5).digit .toRegex(); // -> /\d{3,5}?/ .startOfInput Assert the start of input, or the start of a line when .lineByLine is used. Example SuperExpressive() .startOfInput .string('hello') .toRegex(); // -> /^hello/ .endOfInput Assert the end of input, or the end of a line when .lineByLine is used. Example SuperExpressive() .string('hello') .endOfInput .toRegex(); // -> /hello$/ .anyOfChars(chars) Matches any of the characters in the provided string chars. Example SuperExpressive() .anyOfChars('aeiou') .toRegex(); // -> /[aeiou]/ .anythingButChars(chars) Matches any character, except any of those in the provided string chars. Example SuperExpressive() .anythingButChars('aeiou') .toRegex(); // -> /[^aeiou]/ .anythingButString(str) Matches any string the same length as str, except the characters sequentially defined in str. Example SuperExpressive() .anythingButString('aeiou') .toRegex(); // -> /(?:[^a][^e][^i][^o][^u])/ .anythingButRange(a, b) Matches any character, except those that would be captured by the .range specified by a and b. Example SuperExpressive() .anythingButRange(0, 9) .toRegex(); // -> /[^0-9]/ .string(s) Matches the exact string s. Example SuperExpressive() .string('hello') .toRegex(); // -> /hello/ .char(c) Matches the exact character c. Example SuperExpressive() .char('x') .toRegex(); // -> /x/ .range(a, b) Matches any character that falls between a and b. Ordering is defined by a characters ASCII or unicode value. Example SuperExpressive() .range('a', 'z') .toRegex(); // -> /[a-z]/ .subexpression(expr, opts?) * opts.namespace: A string namespace to use on all named capture groups in the subexpression, to avoid naming collisions with your own named groups (default = '') * opts.ignoreFlags: If set to true, any flags this subexpression specifies should be disregarded (default = true) * opts.ignoreStartAndEnd: If set to true, any startOfInput/ endOfInput asserted in this subexpression specifies should be disregarded (default = true) Matches another SuperExpressive instance inline. Can be used to create libraries, or to modularise you code. By default, flags and start/end of input markers are ignored, but can be explcitly turned on in the options object. Example // A reusable SuperExpressive... const fiveDigits = SuperExpressive().exactly(5).digit; SuperExpressive() .oneOrMore.range('a', 'z') .atLeast(3).anyChar .subexpression(fiveDigits) .toRegex(); // -> /[a-z]+.{3,}\d{5}/ .toRegexString() Outputs a string representation of the regular expression that this SuperExpression models. Example SuperExpressive() .allowMultipleMatches .lineByLine .startOfInput .optional.string('0x') .capture .exactly(4).anyOf .range('A', 'F') .range('a', 'f') .range('0', '9') .end() .end() .endOfInput .toRegexString(); // -> "/^(?:0x)?([A-Fa-f0-9]{4})$/gm" .toRegex() Outputs the regular expression that this SuperExpression models. Example SuperExpressive() .allowMultipleMatches .lineByLine .startOfInput .optional.string('0x') .capture .exactly(4).anyOf .range('A', 'F') .range('a', 'f') .range('0', '9') .end() .end() .endOfInput .toRegex(); // -> /^(?:0x)?([A-Fa-f0-9]{4})$/gm About Super Expressive is a zero-dependency JavaScript library for building regular expressions in (almost) natural language Resources Readme License MIT License Releases No releases published Packages 0 No packages published Used by 15 * @WhatTheFar * @sam-chuang * @WhatTheFar * @WhatTheFar * @francisrstokes * @antwonthegreat * @alloyking1 * @ungvert + 7 Contributors 9 * @francisrstokes * @ckknight * @jcao219 * @skratchdot * @bassim * @KieSun * @jimmyaffatigato * @0xflotus * @w3bdesign Languages * JavaScript 100.0% * (c) 2021 GitHub, Inc. * Terms * Privacy * Security * Status * Help * Contact GitHub * Pricing * API * Training * Blog * About You can't perform that action at this time. You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.