Compiles pattern. The result says whether it was valid and, if not, the error says where it went wrong. Free the regex with free_regex.
#import "Extensions/Regex";
Regular expressions with the syntax and guarantees of Rust's regex crate, full
Unicode support, and patterns that can be compiled while your program compiles. A jaic
extension, not official Jai: other Jai compilers have no such module, and it may change
between jaic releases. See docs/extensions/regex.md.
Regex :: #import "Extensions/Regex";
// Compiled while the program compiles: a bad pattern is a compile error, and named
// groups become typed fields (an integer for a run of digits, an enum for a few words).
Date :: Regex.Static("(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})");
date, ok := Regex.parse(Date, "2026-10-11"); // date.year is a u16, date.month a u8
// Compiled at run time, for a pattern only known then.
user_pattern := "[a-z]+";
text := "one two";
re, compiled, error := Regex.compile(user_pattern);
for Regex.find_all(*re, text) print("% ", it.text);Show moreShow less
Matching takes time linear in the text for every pattern: there are no backreferences and no look-around, and the engines are automata, never an exponential backtracker.
Procedures#
General#
Whether captures for this pattern are found in a single scan (see docs/extensions/regex.md).
The leftmost match at or after byte start.
Every match, left to right, not overlapping. An empty match right where the previous match ended is skipped, and in Unicode mode empty matches never split a UTF-8 sequence.
Group index's text, and whether it took part in the match.
Group index's byte range, or -1, -1.
Replaces the first match. In replacement, $1 / ${1} is a group's text, $name /
${name} a named group's, and $$ a dollar sign; a group that did not match (or does not
exist) gives "". $name takes the longest run of letters, digits and _, so write
${1}st rather than $1st.
Replaces the first limit matches (all of them when limit < 0).
The pieces of text between matches.
text with every regex metacharacter escaped, so it matches literally.
The whole of text against the pattern, with its named groups parsed.
Like parse, into your own struct: each field takes the named group of the same name, and is a
string, integer, float, bool (true / false) or enum (a member's name, any case). A field
with no group or a group with no field is a compile error. False if the text does not match
or a group's text does not fit its field.
Like captures, into your own struct (see parse_into).
Syntax#
Program#
Compiles root. reverse builds the program that reads the text backwards (no captures
and no unanchored start: it is only run back from the end of a match).
Every match begins at the start of the text.
Can only ever match the empty string at a position (a look or nothing), so it can be skipped over when looking for what a concatenation starts with.
NFA#
Whether look holds at pos. The whole text is context, so a search that starts mid-text
still sees the byte before it.
Runs program over text[start .. end] (looks still see all of text). Anchored searches only
try start. Fills slots (the first slots.count of them, -1 for groups that did not take
part: pass two to find only where the match is) and
returns whether anything matched; the match is the leftmost one, and among those, the one
the pattern prefers.
The first match at exactly start within text[start .. end], like an anchored pike_search,
by depth-first search in priority order. Each (instruction, position) is tried once, so this
is linear too, but it needs instructions * (end - start + 1) bits of memory: use it for short
spans only (backtrack_fits).
Onepass#
Builds the table for program (the forward one). ok is false in the result if the pattern
is not one-pass or needs more than state_limit states.
Fills slots (-1 where a group did not take part) with the offsets of the match
text[s .. e] that starts at s, which must be the match the pattern prefers there. False if
the table finds no path that ends exactly at e.
DFA#
Builds every state, so that no search ever needs the program. False if there are more than the limit.
A copy holding only the tables (for a DFA built completely).
The end of the leftmost-first match that starts at or after start (and exactly at start
if anchored), or -1. With earliest, stops at the first position where any match ends,
which answers "is there a match" sooner. gave_up means the DFA grew past its limit and the
caller has to use another matcher.
Run back from end (a reverse DFA): the leftmost position >= bound where a match ending at
end can start, or -1.
The step over non-ASCII byte text[at] in a DFA with a Unicode \b, through the column that
knows whether a word character starts at at and whether one ends with it.
The skip for an unanchored start (computing it the first time, in a lazy DFA).
The next position at or after i where a match could start, or -1.
Whether the bytes from at can begin a match, as far as the skip's checks tell.
For each of the first few positions of a match, the bytes it can have there, up to the shortest match's length (looks are taken to hold, which only adds bytes).
A rare set of bytes that every match contains, and the bytes a match can have before the first of them. Tries each ASCII byte together with its other case.
The bytes a match can consume before its first byte from required; not ok if a match can
do without one.
A rough share of typical text (mostly English, some UTF-8) that falls in the set.
Search#
The leftmost-first match at or after start: its start and end, or end -1. earliest only
promises to say whether there is one (the end may be early and the start is not computed).
The length every match has, or -1 if they differ (or the program is too big to tell).
Where each group of the match text[s .. e] is.
Runs body for each match with s and e set, following find_all's rules for empty matches.
Generate#
The engine for a constant pattern, built at compile time. A bad pattern is a compile error.
Static's check that its pattern parses; returns no code.
The #modify of every procedure that takes a Static type.
One plan per named group, in group order. ok is false if the pattern does not parse (the error is reported where the engine is built).
The letter a case-insensitive class stands for, written in lower case: (?i)y matches Y and y. Other characters in the class must be outside ASCII (like the Kelvin sign for k).
An identifier in upper snake case, the way enum members are written.
The text a node always matches exactly, if it is a plain string.
Whether a node only matches numbers: an optional sign, digits, and for a float a . and more
digits. digits is the most integer digits it can match, -1 for no limit.
Matches only decimal digits; how many (hi -1: no limit).
The members of Groups(pattern).
Statements that fill out (a *Groups(pattern)) from text and slots; return false when a
number does not fit its field.
Statements that fill out (a *T the caller declared) from text and slots. Every field
must have a named group and every named group a field; anything else is a compile error.
Decimal digits (any script's) with an optional sign, into an integer of type T. False when it does not fit.
A number like 12.5 or -3 (digits from any script) as a float64.
The value of the decimal digit at index and its size in bytes; -1 if it is not one.
Types#
Pattern flags, also settable inside the pattern: (?i) (?m) (?s) (?U) (?x) (?R) (?-u).
A compiled pattern. Copies share the compiled program and the search cache, which is not safe to use from two threads at once: give each thread its own compile.
Where each group matched. Group 0 is the whole match; a group that did not take part has start -1.
A regex compiled while your program compiles: a type, made from a constant pattern.
An unanchored start state usually goes back to itself on most bytes: the search is waiting for the first byte of a match. A vector search jumps to the next place a match could start. Without looks, any position will do as a restart (the start state does not depend on the byte before), so the search can use bytes from further into the match, at a fixed distance from its start: two of them, if no single one is rare. When every byte near the start is common, a rare byte that every match must contain will do: find it, then walk back over the bytes a match can have before it to where the match could start. With looks, it can only jump over bytes that keep the DFA in its start state.
What a named group's field holds.
Constants#
as in Rust; big counts still fail as too large a program
Run-time engines may be bigger than ones frozen into a program.
A non-ASCII byte in a DFA with a Unicode \b: look at the characters around it (see unicode_word).
What a byte looks like to a look: the edge of the text, \n, \r, a word byte, anything else.
a non-ASCII word character: a word for Unicode looks only
A byte rarer than this is searched for alone.
A search whose bytes make up more than this share of typical text stops too often to pay.
Positions into a match that the start analysis looks at.
A required byte rarer than this pays for walking back over the bytes before it.
Bigger than this and the DFA is built lazily at run time instead of stored in the program.