Skip to content
Open Saka

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)? num

Returns 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)? Match

Returns 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)? Match

Returns 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): bool

True 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): bool

True when any substring matches the Reg. A nullable Reg always matches.

starts_with

def lin starts_with(text: str, reg prefix): bool

True when a prefix matches the Reg. A nullable Reg always matches.

ends_with

def lin ends_with(text: str, reg suffix): bool

True when a suffix matches the Reg. A nullable Reg always matches.

matches

def matches(text! str, reg needle+ char)* num -> Match

Returns 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): num

Counts 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 -> Segment

Partitions 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 -> str

Splits 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): str

Replaces 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)! str

Replaces 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): str

Replaces 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)? str

Removes 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)? str

Removes 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.