re
Search, split, and replace text with patterns.
Patterns are capture-free character Regs passed as reg arguments,
not runtime strings. "a+" matches those two literal characters; "a"'+ matches one or more a characters.
Each operation selects spans by one match mode.
Searches choose the earliest start and then the longest match, independently of union order:
re::first("ab", "a" | "ab") returns (start: 0, end: 2, text: "ab").
Indices count Unicode scalars, not bytes, UTF-16 units, or grapheme clusters. Literal operations live in @std/str.saka.
Searches, predicates, and stripping accept nullable patterns: re::first("x", "") returns an empty match at zero,
while re::first("x", {}) returns an empty Bag.
Enumeration, counting, splitting, and replacement require non-nullable patterns.
To select ASCII word-like runs, declare reg word = (alnum | "_")'+, then filter
re::matches(text, word) if m => m.v.text == "cat"; searching for "cat" alone also finds it inside "scatter".
For computed replacement, declare def decorate(match! str)! str = "<\{match}>", then call
re::replace_all_with(text, digit'+, decorate).
Regs recognize text; use Pegs and
compile_parser to extract captured structure.
Write these names after re::, as in re::Match.
Match
set Match = (start: num, end: num, text: str)A match’s half-open Unicode scalar boundaries and matched text. This is a structural record alias.
Segment
set Segment = (matched: bool, text: str)One matched or unmatched piece of a text partition. This is a structural record alias.
find
def find(text! str, reg needle)? numReturns the first Unicode scalar index matched by a Reg, or an empty Bag. A nullable Reg matches at zero; a Reg with an empty language never matches.
first
def first(text! str, reg needle)? MatchReturns the earliest-start, longest Reg match as half-open Unicode scalar boundaries and its text. A nullable Reg starts at zero and still selects the longest match; absence returns an empty Bag.
first_from
def first_from(text! str, reg needle, start! num)? MatchReturns the earliest-start, longest match starting at or after start, with boundaries in the original text.
start counts Unicode scalars. A negative, fractional, or unsafe index causes Conflict, as with str::at.
An index beyond the text returns an empty Bag; at its end only a nullable pattern can match.
full_match
def lin full_match(text: str, reg pattern): boolTrue when the complete input belongs to the Reg language, including empty input. A nullable Reg does not necessarily accept nonempty text; an empty language never matches.
contains
def lin contains(text: str, reg needle): boolTrue when any substring matches the Reg. A nullable Reg always matches.
starts_with
def lin starts_with(text: str, reg prefix): boolTrue when a prefix matches the Reg. A nullable Reg always matches.
ends_with
def lin ends_with(text: str, reg suffix): boolTrue when a suffix matches the Reg. A nullable Reg always matches.
matches
def matches(text! str, reg needle+ char)* num -> MatchReturns nonoverlapping leftmost-longest Reg matches keyed by consecutive zero-based ordinals.
Each match carries half-open Unicode scalar boundaries and its text. The Reg must be non-nullable;
an empty language returns an empty Bag. Match i lies between split pieces i and i + 1.
count
def lin count(text: str, reg needle+ char): numCounts nonoverlapping leftmost-longest matches without constructing match records. The Reg must be non-nullable. Empty input, an empty language, and no matches yield zero.
segments
def segments(text! str, reg pattern+ char)+ num -> SegmentPartitions the text into alternating unmatched and matched pieces with consecutive zero-based keys.
Unmatched pieces take even keys, including empty ones, and match i takes key 2 * i + 1.
Joining every piece in key order reproduces the text; the Reg must be non-nullable.
Always returns at least one piece, including 0 -> (matched: false, text: "") for empty input.
split
def split(text! str, reg separator+ char)+ num -> strSplits on nonoverlapping leftmost-longest Reg separators into consecutive zero-based indexed pieces.
The Reg must be non-nullable. Preserves leading, trailing, and repeated empty pieces.
No separator match yields 0 -> text; empty input yields 0 -> "". Piece i precedes match i.
split_first
def split_first(text! str, reg separator+ char)? (before: str, separator: Match, after: str)Splits once at the earliest-start, longest separator, retaining its match and the complete remainder. The Reg must be non-nullable. No separator match returns an empty Bag; edge matches keep empty pieces.
replace_all
def lin replace_all(text: str, reg needle+ char, replacement: str): strReplaces nonoverlapping leftmost-longest Reg matches, or returns the original text when absent. The Reg must be non-nullable. Replacement text is literal and is not searched again.
replace_all_with
def replace_all_with(text! str, reg needle+ char, def replacement(match! str)! str)! strReplaces each nonoverlapping leftmost-longest match with the result of a pure Flow callback.
The callback receives matched text and must return exactly one string; return "" to delete a match.
The Reg must be non-nullable. Unmatched text is preserved, and replacements are not searched again.
replace
def lin replace(text: str, reg needle+ char, replacement: str): strReplaces the earliest-start, longest Reg match, or returns the original text when absent. The Reg must be non-nullable. Replacement text is literal and is not searched again.
strip_prefix
def strip_prefix(text! str, reg prefix)? strRemoves the longest matching Reg prefix, or returns an empty Bag when unmatched. A nullable Reg succeeds; a longer nonempty match takes precedence over its empty match.
strip_suffix
def strip_suffix(text! str, reg suffix)? strRemoves the longest matching Reg suffix, or returns an empty Bag when unmatched. A nullable Reg succeeds; a longer nonempty match takes precedence over its empty match.