🎮 Playground 💻 Live Demo
Rexx: A human-friendly regex library with structured syntax and variable support.
# Install rexx using npm npm install rexx # using Yarn yarn add rexx # using pnpm pnpm install rexx
<script src="dist/rexx.js"></script> <!--or via CDN--> <script src="https://www.unpkg.com/rexx"></script>
// CommonJS const rexx = require('rexx') // or ES6 Modules import rexx from 'rexx'
Semantic Versioning (SemVer) follows the pattern major.minor.patch, where major, minor, and patch are non-negative integers.
const regExp = rexx(` digits = { one_or_more { digit } } semVer = { begin optional {'v'} group('major') { digits } '.' group('minor') { digits } '.' group('patch') { digits } end } `) console.log(regExp) // { // digits: /\d+/, // semVer: /^v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/, // default: /(?:)/, // } regExp.semVer.test('v1.2.3') // true
A URL contains several components - the protocol, host, path, query, and hash.
http://www.example.com/foo/bar.html?a=b&c=d#hash
const urlRegexp = rexx(` protocol = { optional { one_of{'http', 'https'} } } // http host = { one_or_more { except{'/'} } } // www.example.com path = { loop(0..) {'/', one_or_more { except{'/?#'} } } } // /foo/bar.html query = { optional {'?', one_or_more { except{'#'} } } } // ?a=b&c=d hash = { optional {'#', one_or_more { any } } } // #hash url = { group('protocol'){ protocol } optional{'://'} group('host'){ host } group('path'){ path } group('query'){ query } group('hash'){ hash } } `) console.log(urlRegexp.url) // /(?<protocol>(?:(?:http|https))?)(?:\:\/\/)?(?<host>(?:[^\/])+)(?<path>(?:\/(?:[^\/\?#])+)*)(?<query>(?:\?(?:[^#])+)?)(?<hash>(?:#.+)?)/ urlRegexp.url.test('http://www.example.com/foo/bar.html?a=b&c=d#hash') // true
The password must contain characters from at least 3 of the following 4 rules: upper case, lower case, numbers, non-alphanumeric.
const pwdRegexp = rexx(` lower = { one_of {range {'a', 'z'} } } upper = { one_of {range {'A', 'Z'} } } _any = { loop(0..) { any } } hasLower = { followed_by { _any, lower } } hasUpper = { followed_by { _any, upper } } hasDigit = { followed_by { _any, digit } } hasSymbol = { followed_by { _any, non_word } } password = { begin one_of { {hasLower, hasUpper, hasDigit} {hasLower, hasUpper, hasSymbol} {hasLower, hasDigit, hasSymbol} {hasUpper, hasDigit, hasSymbol} } loop(8..){ any } end } `) console.log(pwdRegexp.password) // /^(?:(?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*\W)|(?=.*[a-z])(?=.*\d)(?=.*\W)|(?=.*[A-Z])(?=.*\d)(?=.*\W)).{8,}$/Rexx RegExp Rexx RegExp one_of { 'a', 'b', 'c' } [abc] word \w one_of { 'foo', 'bar' } foo|bar non_word \W one_of { range {'a', 'z'} } [a-z] digit \d optional {'a'} / loop(0..1) {'a'} a? non_digit \D optional {'abc'} (?:abc)? whitespace \s loop(0..) {'a'} a* non_whitespace \S one_or_more {'a'} / loop(1..) {'a'} a+ boundary \b loop(2) {'a'} a{2} non_boundary \B loop(2..3) {'a'} a{2,3} chinese [\u4e00-\u9fa5] except {'a'} [^a] '\d' \d except { range {'a', 'z'} } [^a-z] '\uffff' \uffff group{'foo'} (foo) newline \n group('year'){'2024'} (?<year>2024) tab \t ref {1} \1 any . ref {year} \k<year> begin ^ followed_by {'a'} (?=a) end $ not_followed_by {'a'} (?!a) global g preceded_by {'a'} (?<=) ignore_case i not_preceded_by {'a'} (?<!) multiline m loop (1..) {'a'} lazy a+?
Matches exact characters.
Example: 'foo'
in Rexx translates to foo
in regex.
Syntax: one_of { pattern, pattern, ... }
Matches any one of the listed alternatives. Commas are optional.
Example: one_of { 'foo', 'bar' }
translates to foo|bar
in regex.
Syntax: range { 'start', 'end' }
Creates a range of characters.
Example: one_of { range { 'a', 'z' } }
translates to [a-z]
.
Syntax: optional { pattern }
Marks the pattern as optional.
Example: optional { 'foo' }
translates to foo?
.
Syntax: loop(from..to) { pattern }
or loop(times) { pattern }
Specifies a pattern to repeat.
Example: loop(1..3) { 'a' }
translates to a{1,3}
.
Syntax: except { pattern }
Matches any character except the given pattern.
Example: except { 'a' }
becomes [^a]
.
Syntax: group { pattern }
or group('name') { pattern }
Capturing group is assigned a name or sequential number.
Example: group { 'abc' }
or group('name'){ 'abc' }
translates to (abc)
or (?<name>abc).
Syntax: ref { 1 }
or ref { 'name' }
References a previously matched group.
Example: ref { 1 }
or ref { 'name' }
translates to \1
or \k<name>
.
Syntax: followed_by { 'pattern' }
Asserts that what follows the current position is the specified pattern.
Example: followed_by { 'a' }
translates to (?=a)
.
Syntax: not_followed_by { 'pattern' }
Asserts that what follows the current position is not the specified pattern.
Example: not_followed_by { 'a' }
translates to (?!a)
.
Syntax: preceded_by { 'pattern' }
Asserts that what precedes the current position is the specified pattern.
Example: preceded_by { 'a' }
translates to (?<=a)
.
Syntax: not_preceded_by { 'pattern' }
Asserts that what precedes the current position is not the specified pattern.
Example: not_preceded_by { 'a' }
translates to (?<!a)
.
Syntax: // This is a comment
Adds a comment to the pattern for explanation.
variable_name = { pattern }
.ignore_case
, global
, multiline
.digits = { one_or_more { digit } } semVer = { begin optional {'v'} group('major') { digits } '.' group('minor') { digits } '.' group('patch') { digits } end } // /^v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/
<start>; option of "v"; capture major { some of <digit>; } "."; capture minor { some of <digit>; } "."; capture patch { some of <digit>; } <end>; // /^v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/
import { createRegExp, maybe, oneOrMore, exactly, digit } from 'magic-regexp' const regExp = createRegExp( maybe('v') .and(oneOrMore(digit).groupedAs('major')) .and(exactly('.')) .and(oneOrMore(digit).groupedAs('minor')) .and(exactly('.')) .and(oneOrMore(digit).groupedAs('patch')) .at.lineStart() .at.lineEnd() ) // /^v?(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/
const regExp = VerEx() .startOfLine() .maybe('v') .beginCapture() .digit().oneOrMore() .endCapture() .then('.') .beginCapture() .digit().oneOrMore() .endCapture() .then('.') .beginCapture() .digit().oneOrMore() .endCapture() .endOfLine() // /^(?:v)?(\d+)(?:\.)(\d+)(?:\.)(\d+)$/
Contributions to this project are welcome.
Clone and fork:
git clone https://github.com/yyytcool/rexx.git
Copyright (c) 2024-present, yyytcool
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3