Regex
● Intermediate5 minBefore this: StringsSpec 14.8
A regular expression is a pattern that text can match. regex.new makes one; its methods find, capture, replace and split.
use std.regex
fn main() ! Error {
const email = try regex.new(r"^[\w.+-]+@[\w-]+\.[\w.]+$")
print(email.is_match("asha@example.com"))
print(email.is_match("asha at example"))
const date = try regex.new(r"(?<year>\d{4})-(?<month>\d{2})")
const parts = date.named_captures("due 2026-10") ?? [:]
print(parts["year"] ?? "")
print(parts["month"] ?? "")
}The program ran and printed:
kavach run match.kav
truefalse202610
- Write patterns as raw strings,
r"…", so\dneeds no extra backslash. (?<year>…)is a named group;named_capturesgives each one by name.
Find, split, replace
use std.regex
fn main() ! Error {
const number = try regex.new(r"\d+")
print(number.find("order 42 of 7") ?? "none")
print(number.find_all("order 42 of 7, room 301"))
const spaces = try regex.new(r"\s*,\s*")
print(spaces.split("mango , fig, tea"))
}The program ran and printed:
kavach run find.kav
42["42", "7", "301"]["mango", "fig", "tea"]
use std.regex
fn main() ! Error {
const date = try regex.new(r"(?<day>\d{2})/(?<month>\d{2})/(?<year>\d{4})")
print(date.replace_all("from 03/11/2026 to 10/11/2026", r"${year}-${month}-${day}"))
const card = try regex.new(r"\d{4} \d{4} \d{4} (\d{4})")
print(card.replace("card 4242 4242 4242 1881", r"**** **** **** $1"))
}The program ran and printed:
kavach run replace.kav
from 2026-11-03 to 2026-11-10card **** **** **** 1881
In the replacement, ${year} and $1 insert a group: a raw string keeps {…} from being read as interpolation.
A pattern that is wrong
use std.regex
fn main() {
const pattern = regex.new(r"(\d+") catch e => {
print("bad pattern: {e}")
return
}
print(pattern)
}The program ran and printed:
kavach run bad.kav
bad pattern: invalid pattern `(\d+`: unclosed groupEvery method
| Method | Gives |
|---|---|
is_match(text) | Whether the pattern matches anywhere in text |
find(text) | The first match, or none |
find_all(text) | Every match that doesn't overlap the one before |
captures(text) | For the first match: the whole match then each group, none for a group that didn't take part; or none without a match |
named_captures(text) | For the first match: each named group that took part, by name; or none |
replace(text, with), replace_all(text, with) | The text with the first or every match replaced; in with, $1 and ${name} insert a group (write with as a raw string, r"${name}", so {…} is not interpolation) |
split(text) | The parts of text between matches |
regex.new matches in time proportional to the text, whatever the pattern, so text from users can't make it hang. regex.advanced also allows lookaround and backreferences, and gives up after a fixed amount of work.