Regular expressions
A regular expression is written between slashes, optionally followed by flags:
/pattern/flags
| Flag | Meaning |
|---|---|
i | Ignore case |
m | Multi-line: ^ and $ match at line breaks |
The syntax and semantics are those of JavaScript regular expressions (ECMAScript). They include
character classes, quantifiers (greedy and lazy), groups, backreferences, lookahead and
lookbehind, and Unicode escapes. jlens uses the regress engine,
which follows the ECMAScript specification. An invalid pattern fails with S0302.
Like JavaScript’s, the engine backtracks, so some patterns take exponential time on inputs they
almost match: /^(a+)+$/ on thirty a followed by ! tries half a billion ways to split the
run. When the evaluation has a timeout or a cancellation token, a match stops with D1012 or
U1003 like any other step (ADR 0009). Set a timeout when
the expressions come from users.
Functions that take a regular expression
$containstests whether a string matches.$matchreturns the matches, with positions and groups.$replacereplaces matches, with references to groups.$splitsplits a string around matches.
input: address.json
Email.address[$contains($, /@my-work\./)]
=> ["fred.smith@my-work.com", "fsmith@my-work.com"]
$replace("2024-03-15", /(\d+)-(\d+)-(\d+)/, "$3/$2/$1")
=> "15/03/2024"
Matching in predicates
A regular expression is a function: applied to a string, it returns the first match, or
nothing. With the chain operator ~>, that makes a compact test in a filter:
input: invoice.json
Account.Order.Product[`Product Name` ~> /hat/i].`Product Name`
=> ["Bowler Hat", "Trilby hat", "Bowler Hat"]
Matcher functions
Called directly, a regular expression returns an object describing the first match:
match: the matched text;startandend: its positions;groups: the captured texts;next: a function that returns the next match, or nothing.
(
$matcher := /[a-z]*an[a-z]*/i;
$m := $matcher("A man, a plan, a canal, Panama!");
[$m.match, $m.start, $m.end, $m.next().match]
)
=> ["man", 2, 5, "plan"]
$contains, $match, $replace and $split only rely on this contract. Any function that
returns such objects can therefore stand in for a regular expression, for example a lambda
that implements a custom matching rule.
Positions in match objects are character offsets as JavaScript counts them, in UTF-16 code units. A character outside the Basic Multilingual Plane counts as two.
Adapted from the JSONata documentation (MIT license).