francisrstokes / super-expressive
- суббота, 18 июля 2020 г. в 00:24:10
JavaScript
🦜 Super Expressive is a zero-dependency JavaScript library for building regular expressions in (almost) natural language
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 3kb with minification + gzip!).
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:
SuperExpressive().exactly(5).digit
)SuperExpressive turns those complex and unweildy regexes that appear in code reviews into something that can be read, understood, and properly reviewed by your peers - and maintained by anyone!
npm i super-expressive
const SuperExpressive = require('super-expressive');
The following example recognises and captures the value of a 16-bit hexadecmal 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})$/
SuperExpressive()
Creates an instance of SuperExpressive
.
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
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
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
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
Uses the u
flag on the regular expression, which indicates that it should use full unicode matching.
Example
SuperExpressive()
.unicode
.string('héllo')
.toRegex();
// ->
/héllo/u
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
Matches any single character. When combined with .singleLine, it also matches newlines.
Example
SuperExpressive()
.anyChar
.toRegex();
// ->
/./
Matches any whitespace character, including the special whitespace characters: \r\n\t\f\v
.
Example
SuperExpressive()
.whitespaceChar
.toRegex();
// ->
/\s/
Matches any non-whitespace character, excluding also the special whitespace characters: \r\n\t\f\v
.
Example
SuperExpressive()
.nonWhitespaceChar
.toRegex();
// ->
/\S/
Matches any digit from 0-9
.
Example
SuperExpressive()
.digit
.toRegex();
// ->
/\d/
Matches any non-digit.
Example
SuperExpressive()
.nonDigit
.toRegex();
// ->
/\D/
Matches any alpha-numeric (a-z, A-Z, 0-9
) characters, as well as _
.
Example
SuperExpressive()
.word
.toRegex();
// ->
/\w/
Matches any non alpha-numeric (a-z, A-Z, 0-9
) characters, excluding _
as well.
Example
SuperExpressive()
.nonWord
.toRegex();
// ->
/\W/
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/
Matches (without consuming any characters) at the position between two characters matched by .word.
Example
SuperExpressive()
.digit
.nonWordBoundary
.toRegex();
// ->
/\d\B/
Matches a \n
character.
Example
SuperExpressive()
.newline
.toRegex();
// ->
/\n/
Matches a \r
character.
Example
SuperExpressive()
.carriageReturn
.toRegex();
// ->
/\r/
Matches a \t
character.
Example
SuperExpressive()
.tab
.toRegex();
// ->
/\t/
Matches a \u0000
character (ASCII 0
).
Example
SuperExpressive()
.nullByte
.toRegex();
// ->
/\0/
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])/
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)/
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();
// ->
/(?<interestingStuff>[a-f][0-9]XXX)/
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();
// ->
/(?<interestingStuff>[a-f][0-9]XXX)something else\k<interestingStuff>/
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/
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)?/
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]))/
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]/
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]/
Assert that the proceeding element may or may not be matched.
Example
SuperExpressive()
.optional.digit
.toRegex();
// ->
/\d?/
Assert that the proceeding element may not be matched, or may be matched multiple times.
Example
SuperExpressive()
.zeroOrMore.digit
.toRegex();
// ->
/\d*/
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*?/
Assert that the proceeding element may be matched once, or may be matched multiple times.
Example
SuperExpressive()
.oneOrMore.digit
.toRegex();
// ->
/\d+/
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+?/
Assert that the proceeding element will be matched exactly n
times.
Example
SuperExpressive()
.exactly(5).digit
.toRegex();
// ->
/\d{5}/
Assert that the proceeding element will be matched at least n
times.
Example
SuperExpressive()
.atLeast(5).digit
.toRegex();
// ->
/\d{5,}/
Assert that the proceeding element will be matched somewhere between x
and y
times.
Example
SuperExpressive()
.between(3, 5).digit
.toRegex();
// ->
/\d{3,5}/
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}?/
Assert the start of input, or the start of a line when .lineByLine is used.
Example
SuperExpressive()
.startOfInput
.string('hello')
.toRegex();
// ->
/^hello/
Assert the end of input, or the end of a line when .lineByLine is used.
Example
SuperExpressive()
.string('hello')
.endOfInput
.toRegex();
// ->
/end$/
Matches any of the characters in the provided string chars
.
Example
SuperExpressive()
.anyOfChars('aeiou')
.toRegex();
// ->
/[aeiou]/
Matches any character, except any of those in the provided string chars
.
Example
SuperExpressive()
.anythingButChars('aeiou')
.toRegex();
// ->
/[^aeiou]/
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])/
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]/
Matches the exact string s
.
Example
SuperExpressive()
.string('hello')
.toRegex();
// ->
/hello/
Matches the exact character c
.
Example
SuperExpressive()
.char('x')
.toRegex();
// ->
/x/
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]/
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"
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
.toRegexString();
// ->
/^(?:0x)?([A-Fa-f0-9]{4})$/gm