# Regex `re/*` is the PCRE2-backed regular-expression namespace. Patterns are ordinary strings, compiled on demand and cached; `re/find` and friends report match positions in codepoint indices — the same coordinate system as `len` and `slice` — so results feed straight back into string operations. The functions are part of the stdlib and need no import. Regex literals also appear directly in `match` arms; see Pattern Matching. ## Functions | Function | Purpose | |---|---| | `re/match s pattern` | `true` if the pattern matches anywhere in `s` (search, not full-string) | | `re/find s pattern` | First match as `%{ :match :start :end :groups }`, or nil | | `re/find-all s pattern` | List of non-overlapping match maps | | `re/replace s pattern replacement` | Replace the first match; `$1`, `${name}` backrefs | | `re/replace-all s pattern replacement` | Replace every match; `$1`, `${name}` backrefs | | `re/split s pattern` | Split on every match; capture groups are not kept | | `re/captures s pattern` | List of capture strings (`0` = full match), or nil | | `re/find-at s pattern offset` | First match at or after codepoint `offset` | | `re/escape text` | Escape regex metacharacters so `text` matches literally | | `re/clear-cache` | Free every compiled pattern from the internal cache | | `re/scan-first s patterns offset` | First of `patterns` (a vector of strings) matching exactly at codepoint `offset`; map with `:index`, or nil | Notes: - `re/find` returns `%{ :match ... :start N :end N :groups ... }` with `:start` / `:end` as codepoint slice coordinates, so `[chars/slice $s $start $end]` extracts the match text. `:groups` is a map for named captures (`(?<name>...)`), a vector for positional groups, and `@{}` when the pattern has no groups. - `re/captures` returns the full match at index 0 followed by the positional capture groups. For named captures, use `re/find` — its `:groups` map is keyed by name. - `re/match` is a plain search: `[re/match "abc123" "\d+"]` is `true`. Anchor with `\A...\z` (or `^...$` with the appropriate flags) when you need a full-string test. - Invalid patterns do not raise: `re/match` returns `false`, and the find / replace / split family returns nil. - `re/scan-first` is anchored: each pattern is tested at the given offset only (PCRE2 anchored mode), and the lowest pattern index wins. Advance the offset yourself to tokenise a line — it is the primitive behind the editor's syntax highlighter. - Compiled patterns live in a fixed-size per-thread LRU cache, so hot patterns compile once. `re/clear-cache` drops the whole cache, which matters in long-running processes that build patterns dynamically. ## Examples ### Validate and locate
# Search semantics — the pattern may match anywhere in the subject
echo [re/match "user@example.com" "^\\w+@\\w+\\.\\w{2,}$"]   # true

set m [re/find "order 1234 shipped" "\\d+"]
echo $m~match $m~start $m~end                                # 1234 6 10

# :start/:end are codepoint indices — slice the match back out
echo [chars/slice "order 1234 shipped" $m~start $m~end]      # 1234
### Captures
# Positional captures: index 0 is the full match
echo [re/captures "2024-01-15" "(\\d+)-(\\d+)-(\\d+)"]
# => @{2024-01-15 2024 01 15}

# Named captures arrive as a keyword-keyed map on :groups
set m [re/find "2024-01-15" "(?<y>\\d+)-(?<m>\\d+)-(?<d>\\d+)"]
echo $m~groups~y "-" $m~groups~m "-" $m~groups~d             # 2024-01-15
### Replace and split
echo [re/replace "a1b22c" "\\d+" "<$1>"]                     # a<1>b22c
echo [re/replace-all "a1b22c" "\\d+" "#"]                    # a#b#c
echo [re/replace-all "john smith" "(?<f>\\w+) (?<l>\\w+)" "${l}, ${f}"]
# => "smith, john"
echo [re/split "a1b22c" "\\d+"]                              # @{a b c}
echo [re/escape "a.b*c"]                                     # a\.b\*c
### Anchored tokenising with scan-first
set line "let x = 42"
set patterns @{"\\s+" "let" "\\w+" "=" "[0-9]+"}
set pos 0
while ($pos < $line(len)) {
    set hit [re/scan-first $line $patterns $pos]
    if [nil? $hit] { break }
    echo $hit~index $hit~match
    set pos $hit~end
}
`re/scan-first` returns the first pattern that matches exactly at `pos`, letting the caller walk the line token by token. ## See Also - Pattern Matching — regex patterns in `match` - Strings — codepoint indexing and slicing - Chars — single-character classification