Constructs the intersection of two regex. This is useful to combine several constraints into one. For example, to build a regular expression that can validate a new password:
const passwordRegex = RB(/.{12,}/) // 12 letters or more
.and(/[0-9]/) // at least one number
.and(/[A-Z]/) // at least one upper case letter
.and(/[a-z]/) // at least one lower case letter
.toRegExp()
function isValidPassword(str: string) {
return passwordRegex.test(str)
}
In most cases it's simpler and more efficient to match each RegExp
individually:
function isValidPassword(str: string) {
return /.{12,}/.test(str) && /[0-9]/.test(str) && /[A-Z]/.test(str) && /[a-z]/.test(str)
}
However, this is not always possible.
For example, when a third-party interface expect a single RegExp
as input like:
Compute a Brzozowski derivative of the given RegExp
.
TODO: examples.
A generator function
that returns a (potentially infinite) stream of strings that match the given RegExp
.
This can be useful for testing regular expressions.
const emailRegex = /^[a-z]+@[a-z]+\.[a-z]{2,}$/
for (const matchedStr of RB(emailRegex).enumerate()) {
console.log(matchedStr)
}
a@a.aa
b@a.aa
aa@a.aa
c@a.aa
ba@a.aa
a@b.aa
d@a.aa
ca@a.aa
b@b.aa
ab@a.aa
e@a.aa
da@a.aa
c@b.aa
bb@a.aa
aa@b.aa
f@a.aa
ea@a.aa
d@b.aa
cb@a.aa
ba@b.aa
a@aa.aa
g@a.aa
...
If the regular expression matches infinitely many strings then a loop like above won't terminate.
Use the new Iterator helpers
to only get the first N matches, e.g RB(emailRegex).enumerate().take(100)
.
The generator produces a fair enumeration.
That means every string that matches the regular expression is eventually enumerated.
To illustrate, an unfair enumeration of /^(a+|b+)$/
would be:
"a", "aa", "aaa", "aaaa", "aaaaa", ...
because it never produces any strings of b's. A possible fair enumeration is:
"a", "b", "aa", "bb", "aaa", "bbb", "aaaa", "bbbb", ...
Checks if two regular expressions are semantically equivalent, i.e. they match the exact same set of strings.
Constructs the regex complement, i.e. the regex that matches exactly the strings that the current regex is not matching.
TODO: examples.
This is like the regex pipe operator |
(aka. alternation, aka. union, aka. or).
Constructs quantified regular expressions, subsuming all these
regex operators: *
, +
, {n,m}
, ?
.
Returns the number of strings that match the regex or undefined
if there are infinitely many matches.
RB(/^[a-z]$/).size() === 26n
RB(/^[a-z][0-9]$/).size() === 260n
// this one has infinitely many matches:
RB(/^[a-z]*$/).size() === undefined
// that's why the return type is `bigint`;
RB(/^[a-z]{60}/).size() === 7914088058189701615326255069116716194962212229317838559326167922356251403772678373376n
Double counting is often avoided.
For example, RB(/^(hello|hello)$/).size()
is only 1n
and not 2n
.
But it probably still happens.
The value should always be an upper bound though.
Constructs the difference of the current regex and re
.
That is, this returns a new regex which matches all strings that
the current regex matches EXCEPT everything that re
matches.
A wrapper class for JavaScript regular expressions that exposes the utility functions of this library and also provides a DSL for constructing regular expression.